Commit bb787bd7 authored by zeroleak's avatar zeroleak
Browse files

add pool override for miner-fee configuration

parent b1f48db4
......@@ -25,7 +25,17 @@ server.pools[x].denomination: amount in satoshis
server.miner-fees.miner-fee-min: minimum miner-fee accepted for mustMix
server.miner-fees.miner-fee-max: maximum miner-fee accepted for mustMix
server.miner-fees.miner-fee-cap: "soft cap" miner-fee recommended for a new mustMix (should be <= miner-fee-max)
server.miner-fees.min-relay-fee: minimum miner-fee to accumulate for mixing
```
Optional pool override:
```
server.pools[x].miner-fees.miner-fee-min
server.pools[x].miner-fees.miner-fee-max
server.pools[x].miner-fees.miner-fee-cap
server.pools[x].miner-fees.min-relay-fee
```
UTXO should be founded with:<br/>
for mustMix: (*server.mix.denomination* + *server.miner-fees.miner-fee-min*) to (*server.mix.denomination* + *server.miner-fees.miner-fee-max*). New TX0 outputs are capped to (*server.mix.denomination* + *server.miner-fees.miner-fee-cap*).<br/>
for liquidities: (*server.mix.denomination*) to (*server.mix.denomination* + *server.mix.miner-fee-max*)
......@@ -73,7 +83,6 @@ SCode can expire for tx0s confirmed after a specified time.
server.pools[x].anonymity-set = 5
server.pools[x].must-mix-min = 1
server.pools[x].liquidity-min = 1
server.miner-fees.min-relay-fee = 510
```
Mix will start when *anonymity-set* (mustMix + liquidities) are registered.<br/>
......
......@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.samourai.code.whirlpool</groupId>
<artifactId>whirlpool-server</artifactId>
<version>0.23.20</version>
<version>0.23.21-SNAPSHOT</version>
<name>whirlpool-server</name>
<properties>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
......
package com.samourai.whirlpool.server.beans;
import com.samourai.whirlpool.protocol.WhirlpoolProtocol;
import com.samourai.whirlpool.server.config.WhirlpoolServerConfig;
public class Pool {
private String poolId;
......@@ -10,8 +9,7 @@ public class Pool {
private int minMustMix;
private int minLiquidity;
private int anonymitySet;
private WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig;
private long minerFeeMix;
private PoolMinerFee minerFee;
private Mix currentMix;
private InputPool mustMixQueue;
......@@ -24,16 +22,14 @@ public class Pool {
int minMustMix,
int minLiquidity,
int anonymitySet,
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig,
long minerFeeMix) {
PoolMinerFee minerFee) {
this.poolId = poolId;
this.denomination = denomination;
this.poolFee = poolFee;
this.minMustMix = minMustMix;
this.minLiquidity = minLiquidity;
this.anonymitySet = anonymitySet;
this.minerFeeConfig = minerFeeConfig;
this.minerFeeMix = minerFeeMix;
this.minerFee = minerFee;
this.mustMixQueue = new InputPool();
this.liquidityQueue = new InputPool();
......@@ -61,15 +57,15 @@ public class Pool {
}
public long computeMustMixBalanceMin() {
return denomination + minerFeeConfig.getMinerFeeMin();
return denomination + minerFee.getMinerFeeMin();
}
public long computeMustMixBalanceCap() {
return denomination + minerFeeConfig.getMinerFeeCap();
return denomination + minerFee.getMinerFeeCap();
}
public long computeMustMixBalanceMax() {
return denomination + minerFeeConfig.getMinerFeeMax();
return denomination + minerFee.getMinerFeeMax();
}
public String getPoolId() {
......@@ -97,7 +93,7 @@ public class Pool {
}
public long getMinerFeeMix() {
return minerFeeMix;
return minerFee.getMinerFeeMix();
}
public Mix getCurrentMix() {
......@@ -116,8 +112,7 @@ public class Pool {
return liquidityQueue;
}
// for tests
public WhirlpoolServerConfig.MinerFeeConfig _getMinerFeeConfig() {
return minerFeeConfig;
public PoolMinerFee getMinerFee() {
return minerFee;
}
}
package com.samourai.whirlpool.server.beans;
import com.samourai.whirlpool.server.config.WhirlpoolServerConfig;
public class PoolMinerFee {
private long minerFeeMin; // in satoshis
private long minerFeeCap; // in satoshis
private long minerFeeMax; // in satoshis
private long minRelayFee; // in satoshis
private long minerFeeMix; // in satoshis
public PoolMinerFee(
WhirlpoolServerConfig.MinerFeeConfig globalMfg,
WhirlpoolServerConfig.MinerFeeConfig poolMfg,
int mustMixMin) {
overrideFrom(globalMfg);
if (poolMfg != null) {
overrideFrom(poolMfg);
}
this.minerFeeMix = Math.max(minRelayFee, mustMixMin * minerFeeMin);
}
private void overrideFrom(WhirlpoolServerConfig.MinerFeeConfig mfg) {
if (mfg.getMinerFeeMin() > 0) {
this.minerFeeMin = mfg.getMinerFeeMin();
}
if (mfg.getMinerFeeCap() > 0) {
this.minerFeeCap = mfg.getMinerFeeCap();
}
if (mfg.getMinerFeeMax() > 0) {
this.minerFeeMax = mfg.getMinerFeeMax();
}
if (mfg.getMinRelayFee() > 0) {
this.minRelayFee = mfg.getMinRelayFee();
}
}
public long getMinerFeeMin() {
return minerFeeMin;
}
public long getMinerFeeCap() {
return minerFeeCap;
}
public long getMinerFeeMax() {
return minerFeeMax;
}
public long getMinRelayFee() {
return minRelayFee;
}
public long getMinerFeeMix() {
return minerFeeMix;
}
@Override
public String toString() {
return "["
+ minerFeeMin
+ "-"
+ minerFeeCap
+ ", max="
+ minerFeeMax
+ "], minRelayFee="
+ minRelayFee
+ ", minerFeeMix="
+ minerFeeMix;
}
}
......@@ -331,6 +331,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
private long denomination;
private long feeValue;
private Map<Long, Long> feeAccept;
private MinerFeeConfig minerFees;
private int mustMixMin;
private int liquidityMin;
private int anonymitySet;
......@@ -367,6 +368,14 @@ public class WhirlpoolServerConfig extends ServerConfig {
this.feeAccept = feeAccept;
}
public MinerFeeConfig getMinerFees() {
return minerFees;
}
public void setMinerFees(MinerFeeConfig minerFees) {
this.minerFees = minerFees;
}
public int getMustMixMin() {
return mustMixMin;
}
......@@ -390,11 +399,6 @@ public class WhirlpoolServerConfig extends ServerConfig {
public void setAnonymitySet(int anonymitySet) {
this.anonymitySet = anonymitySet;
}
public long getMinerFeeMix(MinerFeeConfig minerFeeConfig) {
return Math.max(
minerFeeConfig.getMinRelayFee(), mustMixMin * minerFeeConfig.getMinerFeeMin());
}
}
public static class RpcClientConfig {
......@@ -544,6 +548,18 @@ public class WhirlpoolServerConfig extends ServerConfig {
public void setMinRelayFee(long minRelayFee) {
this.minRelayFee = minRelayFee;
}
@Override
public String toString() {
return "["
+ minerFeeMin
+ "-"
+ minerFeeCap
+ ", max="
+ minerFeeMax
+ "], minRelayFee="
+ minRelayFee;
}
}
public static class ScodeSamouraiFeeConfig {
......@@ -636,16 +652,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
int nbSeedWords = samouraiFees.getSecretWallet().getWords().split(" ").length;
configInfo.put("samouraiFees", "secretWallet=(" + nbSeedWords + " seed words)");
configInfo.put(
"minerFees",
"["
+ minerFees.getMinerFeeMin()
+ "-"
+ minerFees.getMinerFeeCap()
+ ", max="
+ minerFees.getMinerFeeMax()
+ "], minRelayFee="
+ minerFees.getMinRelayFee());
configInfo.put("minerFees", minerFees.toString());
configInfo.put(
"registerInput.maxInputsSameHash", String.valueOf(registerInput.maxInputsSameHash));
......@@ -687,13 +694,15 @@ public class WhirlpoolServerConfig extends ServerConfig {
+ (poolConfig.feeAccept != null ? poolConfig.feeAccept : null)
+ ", anonymitySet="
+ poolConfig.anonymitySet;
poolInfo +=
", minerFees="
+ (poolConfig.minerFees != null ? poolConfig.minerFees.toString() : "null");
poolInfo +=
", mustMixMin="
+ poolConfig.getMustMixMin()
+ ", liquidityMin="
+ poolConfig.getLiquidityMin()
+ "], minerFeeMix="
+ poolConfig.getMinerFeeMix(minerFees);
+ "]";
configInfo.put("pools[" + poolConfig.id + "]", poolInfo);
}
int i = 0;
......
......@@ -62,7 +62,11 @@ public class StatusWebController {
poolAttributes.put("anonymitySet", pool.getAnonymitySet());
poolAttributes.put("minMustMix", pool.getMinMustMix());
poolAttributes.put("minLiquidity", pool.getMinLiquidity());
poolAttributes.put("minerFeeMix", pool.getMinerFeeMix());
poolAttributes.put("minerFee", pool.getMinerFee());
pool.getMinerFee().getMinerFeeMin(); // used in template
pool.getMinerFee().getMinerFeeCap(); // used in template
pool.getMinerFee().getMinerFeeMax(); // used in template
pool.getMinerFee().getMinerFeeMix(); // used in template
poolAttributes.put("minerFeeAccumulated", mix.computeMinerFeeAccumulated());
poolAttributes.put("nbInputs", mix.getNbInputs());
poolAttributes.put("nbInputsMustMix", mix.getNbInputsMustMix());
......@@ -125,12 +129,6 @@ public class StatusWebController {
pools.add(poolAttributes);
});
model.addAttribute("pools", pools);
Map<String, Object> minerFees = new HashMap<>();
minerFees.put("minerFeeMin", serverConfig.getMinerFees().getMinerFeeMin());
minerFees.put("minerFeeCap", serverConfig.getMinerFees().getMinerFeeCap());
minerFees.put("minerFeeMax", serverConfig.getMinerFees().getMinerFeeMax());
model.addAttribute("minerFees", minerFees);
return "status";
}
......
......@@ -68,42 +68,41 @@ public class PoolService {
public void __reset() {
WhirlpoolServerConfig.PoolConfig[] poolConfigs = whirlpoolServerConfig.getPools();
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig = whirlpoolServerConfig.getMinerFees();
__reset(poolConfigs, minerFeeConfig);
WhirlpoolServerConfig.MinerFeeConfig globalMinerFeeConfig =
whirlpoolServerConfig.getMinerFees();
__reset(poolConfigs, globalMinerFeeConfig);
}
public void __reset(
WhirlpoolServerConfig.PoolConfig[] poolConfigs,
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig) {
WhirlpoolServerConfig.MinerFeeConfig globalMinerFeeConfig) {
pools = new ConcurrentHashMap<>();
for (WhirlpoolServerConfig.PoolConfig poolConfig : poolConfigs) {
String poolId = poolConfig.getId();
long denomination = poolConfig.getDenomination();
long feeValue = poolConfig.getFeeValue();
Map<Long, Long> feeAccept = poolConfig.getFeeAccept();
int minMustMix = poolConfig.getMustMixMin();
int minLiquidity = poolConfig.getLiquidityMin();
int anonymitySet = poolConfig.getAnonymitySet();
long minerFeeMix = poolConfig.getMinerFeeMix(minerFeeConfig);
Assert.notNull(poolId, "Pool configuration: poolId must not be NULL");
Assert.isTrue(!pools.containsKey(poolId), "Pool configuration: poolId must not be duplicate");
PoolFee poolFee = new PoolFee(feeValue, feeAccept);
Pool pool =
new Pool(
poolId,
denomination,
poolFee,
minMustMix,
minLiquidity,
anonymitySet,
minerFeeConfig,
minerFeeMix);
pools.put(poolId, pool);
metricService.manage(pool);
PoolMinerFee minerFee =
new PoolMinerFee(
globalMinerFeeConfig, poolConfig.getMinerFees(), poolConfig.getMustMixMin());
__reset(poolConfig, minerFee);
}
}
public void __reset(WhirlpoolServerConfig.PoolConfig poolConfig, PoolMinerFee minerFee) {
String poolId = poolConfig.getId();
long denomination = poolConfig.getDenomination();
long feeValue = poolConfig.getFeeValue();
Map<Long, Long> feeAccept = poolConfig.getFeeAccept();
int minMustMix = poolConfig.getMustMixMin();
int minLiquidity = poolConfig.getLiquidityMin();
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");
PoolFee poolFee = new PoolFee(feeValue, feeAccept);
Pool pool =
new Pool(poolId, denomination, poolFee, minMustMix, minLiquidity, anonymitySet, minerFee);
pools.put(poolId, pool);
metricService.manage(pool);
}
public Collection<Pool> getPools() {
return pools.values();
}
......
......@@ -45,7 +45,7 @@
</div>
</td>
<td>
<strong th:text="${pool.nbInputsMustMix}"/> / <span th:text="${pool.minMustMix}"/> mustMix, <strong th:text="${pool.minerFeeAccumulated}"/> / <span th:text="${pool.minerFeeMix}"/> sat<br/>
<strong th:text="${pool.nbInputsMustMix}"/> / <span th:text="${pool.minMustMix}"/> mustMix, <strong th:text="${pool.minerFeeAccumulated}"/> / <span th:text="${pool.minerFee.minerFeeMix}"/> sat<br/>
<strong th:text="${pool.nbInputsLiquidities}"/> / <span th:text="${pool.minLiquidity}"/> liquidities<br/>
<strong th:text="${pool.nbInputs}"/> / <span th:text="${pool.anonymitySet}"/> confirmed</span>
</td>
......@@ -56,6 +56,7 @@
<td><span th:text="${@templateUtil.duration(pool.elapsedTime/1000)}"/></td>
<td>
Pool fee: <span th:text="${@templateUtil.satoshisToBtc(pool.feeValue)}"/><br/>
Miner fee: <span th:text="${pool.minerFee.minerFeeMin}" title="minerFeeMin"/>-<span th:text="${pool.minerFee.minerFeeMax}" title="minerFeeMax"/> (cap=<span th:text="${pool.minerFee.minerFeeCap}" title="minerFeeMaxCap"/>, minRelay=<span th:text="${pool.minerFee.minRelayFee}" title="minRelayFee"/>)<br/>
</td>
</tr>
<tr>
......@@ -88,9 +89,6 @@
</div>
</tbody>
</table>
<p>
Miner fee: <span th:text="${minerFees.minerFeeMin}" title="minerFeeMin"/>-<span th:text="${minerFees.minerFeeCap}" title="minerFeeCap"/> (max <span th:text="${minerFees.minerFeeMax}" title="minerFeeMax"/>)<br/>
</p>
</div>
</body>
</html>
\ No newline at end of file
......@@ -13,6 +13,7 @@ import com.samourai.whirlpool.cli.config.CliConfig;
import com.samourai.whirlpool.client.utils.ClientCryptoService;
import com.samourai.whirlpool.server.beans.Mix;
import com.samourai.whirlpool.server.beans.Pool;
import com.samourai.whirlpool.server.beans.PoolMinerFee;
import com.samourai.whirlpool.server.beans.rpc.RpcTransaction;
import com.samourai.whirlpool.server.beans.rpc.TxOutPoint;
import com.samourai.whirlpool.server.config.WhirlpoolServerConfig;
......@@ -119,17 +120,20 @@ public abstract class AbstractIntegrationTest {
}
protected void configurePools(
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig,
WhirlpoolServerConfig.MinerFeeConfig globalMinerFeeConfig,
WhirlpoolServerConfig.PoolConfig... poolConfigs) {
poolService.__reset(poolConfigs, minerFeeConfig);
poolService.__reset(poolConfigs, globalMinerFeeConfig);
mixService.__reset();
}
protected Mix __nextMix(
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig,
WhirlpoolServerConfig.PoolConfig poolConfig)
protected void configurePool(PoolMinerFee minerFee, WhirlpoolServerConfig.PoolConfig poolConfig) {
poolService.__reset(poolConfig, minerFee);
mixService.__reset();
}
protected Mix __nextMix(PoolMinerFee minerFee, WhirlpoolServerConfig.PoolConfig poolConfig)
throws IllegalInputException {
configurePools(minerFeeConfig, poolConfig);
configurePool(minerFee, poolConfig);
Pool pool = poolService.getPool(poolConfig.getId());
Mix mix = mixService.__nextMix(pool);
return mix;
......@@ -154,22 +158,19 @@ public abstract class AbstractIntegrationTest {
poolConfig.setLiquidityMin(liquidityMin);
poolConfig.setAnonymitySet(anonymitySet);
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig =
WhirlpoolServerConfig.MinerFeeConfig globalMinerFeeConfig =
new WhirlpoolServerConfig.MinerFeeConfig();
minerFeeConfig.setMinerFeeMin(minerFeeMin);
minerFeeConfig.setMinerFeeCap(minerFeeCap);
minerFeeConfig.setMinerFeeMax(minerFeeMax);
globalMinerFeeConfig.setMinerFeeMin(minerFeeMin);
globalMinerFeeConfig.setMinerFeeCap(minerFeeCap);
globalMinerFeeConfig.setMinerFeeMax(minerFeeMax);
PoolMinerFee minerFee = new PoolMinerFee(globalMinerFeeConfig, null, mustMixMin);
// run new mix for the pool
return __nextMix(minerFeeConfig, poolConfig);
return __nextMix(minerFee, poolConfig);
}
protected Mix __nextMix(
int mustMixMin,
int liquidityMin,
int anonymitySet,
Pool copyPool,
WhirlpoolServerConfig.MinerFeeConfig minerFeeConfig)
protected Mix __nextMix(int mustMixMin, int liquidityMin, int anonymitySet, Pool copyPool)
throws IllegalInputException {
// create new pool
WhirlpoolServerConfig.PoolConfig poolConfig = new WhirlpoolServerConfig.PoolConfig();
......@@ -182,13 +183,7 @@ public abstract class AbstractIntegrationTest {
poolConfig.setAnonymitySet(anonymitySet);
// run new mix for the pool
return __nextMix(minerFeeConfig, poolConfig);
}
protected Mix __nextMix(int mustMixMin, int liquidityMin, int anonymitySet, Pool copyPool)
throws IllegalInputException {
return __nextMix(
mustMixMin, liquidityMin, anonymitySet, copyPool, copyPool._getMinerFeeConfig());
return __nextMix(copyPool.getMinerFee(), poolConfig);
}
protected Mix __getCurrentMix() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment