Commit 15d97806 authored by zeroleak's avatar zeroleak
Browse files

add server.pools[x].liquidity-min

parent 8f20e468
......@@ -45,7 +45,7 @@ Standard fee configuration is through *fee-value*.
```
server.register-input.min-confirmations-must-mix: minimum confirmations for mustMix inputs
server.register-input.min-confirmations-liquidity: minimum confirmations for liquidity inputs
```
server.register-input.liquidity-interval = 10: liquidities are added by batch at this frequency
### UTXO rules
```
......@@ -70,14 +70,13 @@ server.pools[x].anonymity-set-max = 20
server.pools[x].anonymity-set-adjust-timeout = 120
server.pools[x].must-mix-min = 1
server.pools[x].liquidity-interval = 10
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/>
At the beginning of the mix, only mustMix can register. Meanwhile, liquidities connecting are placed on a waiting pool.<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.
Liquidities are added by batch every *liquidity-interval*.
### Exports
Each mix success/fail is appended to a CSV file:
......
......@@ -98,6 +98,10 @@ public class Mix {
return getNbInputsMustMix() >= pool.getMinMustMix();
}
public boolean hasMinLiquidityMixReached() {
return getNbInputsLiquidities() >= pool.getMinLiquidity();
}
public boolean isFull() {
return (getNbInputs() >= pool.getMaxAnonymitySet());
}
......
......@@ -10,6 +10,7 @@ public class Pool {
private long minerFeeCap; // in satoshis
private long minerFeeMax; // in satoshis
private int minMustMix;
private int minLiquidity;
private int targetAnonymitySet;
private int minAnonymitySet;
private int maxAnonymitySet;
......@@ -27,6 +28,7 @@ public class Pool {
long minerFeeCap,
long minerFeeMax,
int minMustMix,
int minLiquidity,
int targetAnonymitySet,
int minAnonymitySet,
int maxAnonymitySet,
......@@ -38,6 +40,7 @@ public class Pool {
this.minerFeeCap = minerFeeCap;
this.minerFeeMax = minerFeeMax;
this.minMustMix = minMustMix;
this.minLiquidity = minLiquidity;
this.targetAnonymitySet = targetAnonymitySet;
this.minAnonymitySet = minAnonymitySet;
this.maxAnonymitySet = maxAnonymitySet;
......@@ -107,6 +110,10 @@ public class Pool {
return minMustMix;
}
public int getMinLiquidity() {
return minLiquidity;
}
public int getTargetAnonymitySet() {
return targetAnonymitySet;
}
......
......@@ -288,6 +288,7 @@ public class WhirlpoolServerConfig {
private long minerFeeCap;
private long minerFeeMax;
private int mustMixMin;
private int liquidityMin;
private int anonymitySetTarget;
private int anonymitySetMin;
private int anonymitySetMax;
......@@ -357,6 +358,14 @@ public class WhirlpoolServerConfig {
this.mustMixMin = mustMixMin;
}
public int getLiquidityMin() {
return liquidityMin;
}
public void setLiquidityMin(int liquidityMin) {
this.liquidityMin = liquidityMin;
}
public int getAnonymitySetTarget() {
return anonymitySetTarget;
}
......@@ -519,9 +528,9 @@ public class WhirlpoolServerConfig {
"liquidity="
+ registerInput.minConfirmationsLiquidity
+ ", mustMix="
+ registerInput.minConfirmationsMustMix
+ ", liquidityInterval="
+ String.valueOf(registerInput.liquidityInterval));
+ registerInput.minConfirmationsMustMix);
configInfo.put(
"registerInput.liquidityInterval", String.valueOf(registerInput.liquidityInterval));
String timeoutInfo =
"registerOutput="
......
......@@ -55,6 +55,7 @@ public class StatusWebController {
poolAttributes.put("maxAnonymitySet", pool.getMaxAnonymitySet());
poolAttributes.put("minAnonymitySet", pool.getMinAnonymitySet());
poolAttributes.put("minMustMix", pool.getMinMustMix());
poolAttributes.put("minLiquidity", pool.getMinLiquidity());
poolAttributes.put("minerFeeMin", pool.getMinerFeeMin());
poolAttributes.put("minerFeeCap", pool.getMinerFeeCap());
poolAttributes.put("minerFeeMax", pool.getMinerFeeMax());
......
......@@ -183,6 +183,9 @@ public class MixLimitsService {
return;
}
// add more liquidities
if (log.isDebugEnabled()) {
log.debug("liquidityWatcher.onTimeout => adding more liquidities...");
}
addLiquidities(mix);
}
};
......@@ -243,6 +246,7 @@ public class MixLimitsService {
int liquiditiesToAdd = mix.getPool().getMaxAnonymitySet() - mix.getNbInputs();
if (liquiditiesToAdd > 0) {
// add queued liquidities if any
liquiditiesToAdd++; // invite one more liquidity to prevent more waiting if one disconnects
poolService.inviteToMix(mix, true, liquiditiesToAdd);
} else {
if (log.isDebugEnabled()) {
......
......@@ -119,11 +119,11 @@ public class MixService {
private void validateOnConfirmInput(Mix mix, ConfirmedInput confirmedInput)
throws QueueInputException, IllegalInputException {
RegisteredInput registeredInput = confirmedInput.getRegisteredInput();
Pool pool = mix.getPool();
// verify mix not full
if (mix.isFull()) {
throw new QueueInputException(
"Current mix is full", registeredInput, mix.getPool().getPoolId());
throw new QueueInputException("Current mix is full", registeredInput, pool.getPoolId());
}
// verify not already registered
......@@ -131,10 +131,19 @@ public class MixService {
throw new IllegalInputException("Input already registered for this mix");
}
// liquidity: verify liquidities open
if (registeredInput.isLiquidity() && !mix.isRegisterLiquiditiesOpen()) {
throw new IllegalInputException(
"Current mix not opened to liquidities yet"); // should not happen
if (registeredInput.isLiquidity()) {
// liquidity: verify liquidities open
if (!mix.isRegisterLiquiditiesOpen()) {
throw new IllegalInputException(
"Current mix not opened to liquidities yet"); // should not happen
}
} else {
// mustMix: verify minLiquidity
int liquiditySlotsAvailable = pool.getMaxAnonymitySet() - (mix.getNbInputsMustMix() + 1);
if (liquiditySlotsAvailable < pool.getMinLiquidity()) {
throw new QueueInputException(
"Current mix is full for mustMix", registeredInput, pool.getPoolId());
}
}
// verify max-inputs-same-hash
......@@ -150,18 +159,14 @@ public class MixService {
log.debug("already " + countInputsSameHash + " inputs with same hash: " + inputHash);
}
throw new QueueInputException(
"Current mix is full for inputs with same hash",
registeredInput,
mix.getPool().getPoolId());
"Current mix is full for inputs with same hash", registeredInput, pool.getPoolId());
}
// verify no input address reuse with other inputs
String inputAddress = confirmedInput.getRegisteredInput().getOutPoint().getToAddress();
if (mix.getInputByAddress(inputAddress).isPresent()) {
throw new QueueInputException(
"Current mix is full for inputs with same address",
registeredInput,
mix.getPool().getPoolId());
"Current mix is full for inputs with same address", registeredInput, pool.getPoolId());
}
}
......@@ -286,6 +291,9 @@ public class MixService {
if (!mix.hasMinMustMixReached()) {
return false;
}
if (!mix.hasMinLiquidityMixReached()) {
return false;
}
if (mix.getNbInputs() < mix.getTargetAnonymitySet()) {
return false;
}
......@@ -324,6 +332,10 @@ public class MixService {
+ "/"
+ mix.getPool().getMinMustMix()
+ " mustMix, "
+ mix.getNbInputsLiquidities()
+ "/"
+ mix.getPool().getMinLiquidity()
+ " liquidity, "
+ mix.getNbInputs()
+ "/"
+ mix.getTargetAnonymitySet()
......
......@@ -65,6 +65,7 @@ public class PoolService {
long minerFeeCap = poolConfig.getMinerFeeCap();
long minerFeeMax = poolConfig.getMinerFeeMax();
int minMustMix = poolConfig.getMustMixMin();
int minLiquidity = poolConfig.getLiquidityMin();
int targetAnonymitySet = poolConfig.getAnonymitySetTarget();
int minAnonymitySet = poolConfig.getAnonymitySetMin();
int maxAnonymitySet = poolConfig.getAnonymitySetMax();
......@@ -82,6 +83,7 @@ public class PoolService {
minerFeeCap,
minerFeeMax,
minMustMix,
minLiquidity,
targetAnonymitySet,
minAnonymitySet,
maxAnonymitySet,
......
......@@ -49,6 +49,7 @@ server.pools[0].miner-fee-min = 102
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
......@@ -62,6 +63,7 @@ server.pools[1].miner-fee-min = 102
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
......@@ -75,6 +77,7 @@ server.pools[2].miner-fee-min = 102
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
......
......@@ -25,9 +25,7 @@
<th class="align-middle">PoolId</th>
<th class="align-middle">Denom.<br/>(btc)</th>
<th class="align-middle">Status</th>
<th class="align-middle">Mix users / target<br/>(mustMix + liquidities)</th>
<th class="align-middle">Pool queue<br/>(mustMix + liquidities)</th>
<th class="align-middle">mustMix / min</th>
<th class="align-middle">Users</th>
<th class="align-middle">Elapsed time<br/>(mix)</br.></th>
<th class="align-middle">Configuration</th>
</thead>
......@@ -46,12 +44,9 @@
</div>
</td>
<td>
<span th:text="${pool.nbInputs}" style="font-weight:bold"/> / <span th:text="${pool.targetAnonymitySet}"/><br/>
(<span th:text="${pool.nbInputsMustMix}"/> + <span th:text="${pool.nbInputsLiquidities}"/>)
</td>
<td><span th:text="${pool.mustMixQueued}"/> + <span th:text="${pool.liquiditiesQueued}"/></td>
<td>
<span th:text="${pool.nbInputsMustMix}" style="font-weight:bold"/> / <span th:text="${pool.minMustMix}"/>
<span th:text="${pool.nbInputs}" style="font-weight:bold"/> / <span th:text="${pool.targetAnonymitySet}"/> total<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}"/> queued
</td>
<td><span th:text="${pool.elapsedTime/1000}"/>s</td>
<td>
......
......@@ -123,7 +123,8 @@ public abstract class AbstractIntegrationTest {
throws IllegalInputException {
configurePools(poolConfig);
Pool pool = poolService.getPool(poolConfig.getId());
return mixService.__nextMix(pool);
Mix mix = mixService.__nextMix(pool);
return mix;
}
protected Mix __nextMix(
......@@ -133,6 +134,7 @@ public abstract class AbstractIntegrationTest {
long minerFeeCap,
long minerFeeMax,
int mustMixMin,
int liquidityMin,
int anonymitySetTarget,
int anonymitySetMin,
int anonymitySetMax,
......@@ -148,6 +150,7 @@ public abstract class AbstractIntegrationTest {
poolConfig.setMinerFeeCap(minerFeeCap);
poolConfig.setMinerFeeMax(minerFeeMax);
poolConfig.setMustMixMin(mustMixMin);
poolConfig.setLiquidityMin(liquidityMin);
poolConfig.setAnonymitySetTarget(anonymitySetTarget);
poolConfig.setAnonymitySetMin(anonymitySetMin);
poolConfig.setAnonymitySetMax(anonymitySetMax);
......@@ -157,7 +160,7 @@ public abstract class AbstractIntegrationTest {
return __nextMix(poolConfig);
}
protected Mix __nextMix(int mustMixMin, int anonymitySet, Pool copyPool)
protected Mix __nextMix(int mustMixMin, int liquidityMin, int anonymitySet, Pool copyPool)
throws IllegalInputException {
// create new pool
WhirlpoolServerConfig.PoolConfig poolConfig = new WhirlpoolServerConfig.PoolConfig();
......@@ -169,6 +172,7 @@ public abstract class AbstractIntegrationTest {
poolConfig.setMinerFeeCap(copyPool.getMinerFeeCap());
poolConfig.setMinerFeeMax(copyPool.getMinerFeeMax());
poolConfig.setMustMixMin(mustMixMin);
poolConfig.setLiquidityMin(liquidityMin);
poolConfig.setAnonymitySetTarget(anonymitySet);
poolConfig.setAnonymitySetMin(anonymitySet);
poolConfig.setAnonymitySetMax(anonymitySet);
......
package com.samourai.whirlpool.server.integration;
import com.samourai.wallet.segwit.SegwitAddress;
import com.samourai.whirlpool.server.beans.Mix;
import com.samourai.whirlpool.server.beans.rpc.TxOutPoint;
import com.samourai.whirlpool.server.services.*;
import java.lang.invoke.MethodHandles;
import org.bitcoinj.core.ECKey;
import org.bouncycastle.crypto.params.RSABlindingParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractMixIntegrationTest extends AbstractIntegrationTest {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Autowired protected RegisterInputService registerInputService;
@Autowired protected ConfirmInputService confirmInputService;
@Autowired protected RegisterOutputService registerOutputService;
protected TxOutPoint registerInput(Mix mix, String username, int confirmations, boolean liquidity)
throws Exception {
String poolId = mix.getPool().getPoolId();
ECKey ecKey = new ECKey();
String signature = ecKey.signMessage(poolId);
long inputBalance = mix.getPool().computePremixBalanceMin(liquidity);
TxOutPoint txOutPoint =
createAndMockTxOutPoint(
new SegwitAddress(ecKey.getPubKey(), cryptoService.getNetworkParameters()),
inputBalance,
confirmations);
registerInputService.registerInput(
poolId,
username,
signature,
txOutPoint.getHash(),
txOutPoint.getIndex(),
liquidity,
true,
"127.0.0.1");
return txOutPoint;
}
protected RSABlindingParameters computeBlindingParams(Mix mix) {
RSAKeyParameters serverPublicKey = (RSAKeyParameters) mix.getKeyPair().getPublic();
RSABlindingParameters blindingParams =
clientCryptoService.computeBlindingParams(serverPublicKey);
return blindingParams;
}
protected byte[] registerInputAndConfirmInput(
Mix mix,
String username,
int confirmations,
boolean liquidity,
String receiveAddressOrNullForReuseInputAddr,
RSABlindingParameters blindingParams)
throws Exception {
String mixId = mix.getMixId();
int nbConfirming = mix.getNbConfirmingInputs();
// REGISTER_INPUT
TxOutPoint txOutPoint = registerInput(mix, username, confirmations, liquidity);
boolean queued = (mix.getNbConfirmingInputs() == nbConfirming);
if (queued) {
if (log.isDebugEnabled()) {
log.debug("Not confirming input: it was queued");
}
return null;
}
// blind bordereau
if (receiveAddressOrNullForReuseInputAddr == null) {
// reuse inputAddress
receiveAddressOrNullForReuseInputAddr = txOutPoint.getToAddress();
}
if (blindingParams == null) {
blindingParams = computeBlindingParams(mix);
}
byte[] blindedBordereau =
clientCryptoService.blind(receiveAddressOrNullForReuseInputAddr, blindingParams);
// CONFIRM_INPUT
confirmInputService.confirmInputOrQueuePool(mixId, username, blindedBordereau);
// get a valid signed blinded bordereau
byte[] signedBlindedBordereau =
cryptoService.signBlindedOutput(blindedBordereau, mix.getKeyPair());
return signedBlindedBordereau;
}
}
......@@ -28,6 +28,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeCap = 9500;
long minerFeeMax = 10000;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
......@@ -41,6 +42,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......@@ -79,6 +81,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeCap = 9500;
long minerFeeMax = 10000;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
......@@ -92,6 +95,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......@@ -138,6 +142,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeCap = 9500;
long minerFeeMax = 10000;
int mustMixMin = 3;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
......@@ -151,6 +156,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......
......@@ -382,6 +382,7 @@ public class Whirlpool5WalletsIntegrationTest extends WhirlpoolSimpleIntegration
long minerFeeCap = mixFee * 10 - 2;
long minerFeeMax = mixFee * 10;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
......@@ -395,6 +396,7 @@ public class Whirlpool5WalletsIntegrationTest extends WhirlpoolSimpleIntegration
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......
......@@ -35,6 +35,7 @@ public class WhirlpoolMultiMixIntegrationTest extends AbstractIntegrationTest {
long minerFeeCap = 95000;
long minerFeeMax = 10000;
int mustMixMin = 1;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS_FIRST_MIX;
int anonymitySetMin = 1;
int anonymitySetMax = NB_CLIENTS_FIRST_MIX;
......@@ -48,6 +49,7 @@ public class WhirlpoolMultiMixIntegrationTest extends AbstractIntegrationTest {
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......
......@@ -27,6 +27,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
private AssertMultiClientManager runMustmixWithLiquidities(
int mustMixMin,
int liquidityMin,
int anonymitySetMin,
int anonymitySetTarget,
int anonymitySetMax,
......@@ -51,6 +52,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
minerFeeCap,
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
......@@ -91,6 +93,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
final int NB_MUSTMIX_CONNECTING = 5;
final int NB_LIQUIDITIES_CONNECTING = 5;
int minMustMix = 5;
int minLiquidity = 0;
int minAnonymitySet = 5;
int targetAnonymitySet = 5;
int maxAnonymitySet = 20;
......@@ -101,6 +104,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
AssertMultiClientManager multiClientManager =
runMustmixWithLiquidities(
minMustMix,
minLiquidity,
minAnonymitySet,
targetAnonymitySet,
maxAnonymitySet,
......@@ -117,6 +121,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
final int NB_MUSTMIX_CONNECTING = 5;
final int NB_LIQUIDITIES_CONNECTING = 5;
int minMustMix = 5;
int minLiquidity = 0;
int minAnonymitySet = 5;
int targetAnonymitySet = 5;
int maxAnonymitySet = 8;
......@@ -127,6 +132,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
AssertMultiClientManager multiClientManager =
runMustmixWithLiquidities(
minMustMix,
minLiquidity,
minAnonymitySet,
targetAnonymitySet,
maxAnonymitySet,
......@@ -144,6 +150,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
final int NB_MUSTMIX_CONNECTING = 5;
final int NB_LIQUIDITIES_CONNECTING = 4;
int minMustMix = 2;
int minLiquidity = 0;
int minAnonymitySet = 5;
int targetAnonymitySet = 5;
int maxAnonymitySet = 10;
......@@ -154,6 +161,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
AssertMultiClientManager multiClientManager =
runMustmixWithLiquidities(
minMustMix,
minLiquidity,
minAnonymitySet,
targetAnonymitySet,
maxAnonymitySet,
......@@ -171,6 +179,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
final int NB_MUSTMIX_CONNECTING = 7;
final int NB_LIQUIDITIES_CONNECTING = 7;
int minMustMix = 5;
int minLiquidity = 0;
int minAnonymitySet = 7;
int targetAnonymitySet = 7;
int maxAnonymitySet = 20;
......@@ -181,6 +190,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
AssertMultiClientManager multiClientManager =
runMustmixWithLiquidities(
minMustMix,
minLiquidity,
minAnonymitySet,
targetAnonymitySet,
maxAnonymitySet,
......@@ -197,6 +207,7 @@ public class WhirlpoolMustMixWithLiquiditiesIntegrationTest extends AbstractInte
final int NB_MUSTMIX_CONNECTING = 15;
final int NB_LIQUIDITIES_CONNECTING = 20;
int minMustMix = 15;
int minLiquidity = 0;
int minAnonymitySet = 7;