Commit c1d98d81 authored by zeroleak's avatar zeroleak
Browse files

add pool.tx0MaxOutputs

parent fa725fdf
......@@ -22,6 +22,7 @@ The node will be used to verify UTXO and broadcast tx.
### Pool: UTXO amounts
```
server.pools[x].denomination: amount in satoshis
server.pools[x].tx0MaxOutputs: max outputs per tx0
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)
......
......@@ -9,6 +9,7 @@ public class Pool {
private int minMustMix;
private int minLiquidity;
private int anonymitySet;
private int tx0MaxOutputs;
private PoolMinerFee minerFee;
private Mix currentMix;
......@@ -22,6 +23,7 @@ public class Pool {
int minMustMix,
int minLiquidity,
int anonymitySet,
int tx0MaxOutputs,
PoolMinerFee minerFee) {
this.poolId = poolId;
this.denomination = denomination;
......@@ -29,6 +31,7 @@ public class Pool {
this.minMustMix = minMustMix;
this.minLiquidity = minLiquidity;
this.anonymitySet = anonymitySet;
this.tx0MaxOutputs = tx0MaxOutputs;
this.minerFee = minerFee;
this.mustMixQueue = new InputPool();
......@@ -92,6 +95,10 @@ public class Pool {
return anonymitySet;
}
public int getTx0MaxOutputs() {
return tx0MaxOutputs;
}
public long getMinerFeeMix() {
return minerFee.getMinerFeeMix();
}
......
......@@ -335,6 +335,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
private int mustMixMin;
private int liquidityMin;
private int anonymitySet;
private int tx0MaxOutputs;
public String getId() {
return id;
......@@ -399,6 +400,29 @@ public class WhirlpoolServerConfig extends ServerConfig {
public void setAnonymitySet(int anonymitySet) {
this.anonymitySet = anonymitySet;
}
public int getTx0MaxOutputs() {
return tx0MaxOutputs;
}
public void setTx0MaxOutputs(int tx0MaxOutputs) {
this.tx0MaxOutputs = tx0MaxOutputs;
}
public String toString() {
String poolInfo = "denomination=" + Utils.satoshisToBtc(denomination);
poolInfo +=
", feeValue="
+ Utils.satoshisToBtc(feeValue)
+ ", feeAccept="
+ (feeAccept != null ? feeAccept : null)
+ ", anonymitySet="
+ anonymitySet;
poolInfo += ", minerFees=" + (minerFees != null ? minerFees.toString() : "null");
poolInfo += ", mustMixMin=" + getMustMixMin() + ", liquidityMin=" + getLiquidityMin() + "]";
poolInfo += ", tx0MaxOutputs=" + tx0MaxOutputs;
return poolInfo;
}
}
public static class RpcClientConfig {
......@@ -686,24 +710,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
+ ", expiration="
+ ban.expiration);
for (PoolConfig poolConfig : pools) {
String poolInfo = "denomination=" + Utils.satoshisToBtc(poolConfig.denomination);
poolInfo +=
", feeValue="
+ Utils.satoshisToBtc(poolConfig.feeValue)
+ ", feeAccept="
+ (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()
+ "]";
configInfo.put("pools[" + poolConfig.id + "]", poolInfo);
configInfo.put("pools[" + poolConfig.id + "]", poolConfig.toString());
}
int i = 0;
for (Map.Entry<String, ScodeSamouraiFeeConfig> feePayloadEntry :
......
......@@ -64,6 +64,7 @@ public class PoolsController extends AbstractRestController {
pool.computeMustMixBalanceMax(),
pool.getAnonymitySet(),
pool.getMinMustMix(),
pool.getTx0MaxOutputs(),
nbRegistered,
pool.getAnonymitySet(),
currentMix.getMixStatus(),
......
......@@ -8,9 +8,7 @@ import com.samourai.whirlpool.protocol.rest.Tx0NotifyRequest;
import com.samourai.whirlpool.server.beans.PoolFee;
import com.samourai.whirlpool.server.beans.export.ActivityCsv;
import com.samourai.whirlpool.server.config.WhirlpoolServerConfig;
import com.samourai.whirlpool.server.services.ExportService;
import com.samourai.whirlpool.server.services.FeeValidationService;
import com.samourai.whirlpool.server.services.PoolService;
import com.samourai.whirlpool.server.services.*;
import com.samourai.whirlpool.server.utils.Utils;
import com.samourai.xmanager.client.XManagerClient;
import com.samourai.xmanager.protocol.XManagerService;
......@@ -35,6 +33,9 @@ public class Tx0Controller extends AbstractRestController {
private ExportService exportService;
private WhirlpoolServerConfig serverConfig;
private XManagerClient xManagerClient;
private BlockchainDataService blockchainDataService;
private TaskService taskService;
private MetricService metricService;
@Autowired
public Tx0Controller(
......@@ -42,23 +43,46 @@ public class Tx0Controller extends AbstractRestController {
FeeValidationService feeValidationService,
ExportService exportService,
WhirlpoolServerConfig serverConfig,
XManagerClient xManagerClient) {
XManagerClient xManagerClient,
BlockchainDataService blockchainDataService,
TaskService taskService,
MetricService metricService) {
this.poolService = poolService;
this.feeValidationService = feeValidationService;
this.exportService = exportService;
this.serverConfig = serverConfig;
this.xManagerClient = xManagerClient;
this.blockchainDataService = blockchainDataService;
this.taskService = taskService;
this.metricService = metricService;
}
@RequestMapping(value = WhirlpoolEndpoint.REST_TX0_NOTIFY, method = RequestMethod.POST)
public void tx0Notify(HttpServletRequest request, @RequestBody Tx0NotifyRequest payload)
throws Exception {
public void tx0Notify(HttpServletRequest request, @RequestBody Tx0NotifyRequest payload) {
if (payload.txid == null || payload.poolId == null) {
// ignore old clients
return;
}
if (log.isDebugEnabled()) {
log.debug("(<) " + WhirlpoolEndpoint.REST_TX0_NOTIFY + " " + payload.txid);
log.debug(
"(<) " + WhirlpoolEndpoint.REST_TX0_NOTIFY + " [" + payload.poolId + "]" + payload.txid);
}
// verify tx0
// TODO
// TODO validate & metric
/*
// run tx0 analyzis in another thread
taskService.runOnce(1, () -> {
try {
// verify tx0
RpcTransaction rpcTransaction =
blockchainDataService.getRpcTransaction(payload.txid).orElseThrow(() -> notFoundException);
metricService.onTx0(payload, payload.poolId);
} catch (Exception e) {
log.error("tx0Notify failed", e);
}
});
*/
}
@RequestMapping(value = WhirlpoolEndpoint.REST_TX0_DATA, method = RequestMethod.GET)
......
......@@ -67,6 +67,7 @@ public class StatusWebController {
pool.getMinerFee().getMinerFeeCap(); // used in template
pool.getMinerFee().getMinerFeeMax(); // used in template
pool.getMinerFee().getMinerFeeMix(); // used in template
poolAttributes.put("tx0MaxOutputs", pool.getTx0MaxOutputs());
poolAttributes.put("minerFeeAccumulated", mix.computeMinerFeeAccumulated());
poolAttributes.put("nbInputs", mix.getNbInputs());
poolAttributes.put("nbInputsMustMix", mix.getNbInputsMustMix());
......
......@@ -31,7 +31,7 @@ public class BlockchainDataService {
this.bech32Util = bech32Util;
}
protected Optional<RpcTransaction> getRpcTransaction(String txid) {
public Optional<RpcTransaction> getRpcTransaction(String txid) {
if (log.isTraceEnabled()) {
log.trace("RPC query: getRawTransaction " + txid);
}
......
......@@ -93,12 +93,21 @@ public class PoolService {
int minMustMix = poolConfig.getMustMixMin();
int minLiquidity = poolConfig.getLiquidityMin();
int anonymitySet = poolConfig.getAnonymitySet();
int tx0MaxOutputs = poolConfig.getTx0MaxOutputs();
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);
new Pool(
poolId,
denomination,
poolFee,
minMustMix,
minLiquidity,
anonymitySet,
tx0MaxOutputs,
minerFee);
pools.put(poolId, pool);
metricService.manage(pool);
}
......
......@@ -20,11 +20,6 @@ spring.datasource.password=CONFIGURE-ME
server.samourai-fees.secret-wallet.words = CONFIGUREME
server.samourai-fees.secret-wallet.passphrase = CONFIGUREME
server.miner-fees.miner-fee-min = 170
server.miner-fees.miner-fee-cap = 9500
server.miner-fees.miner-fee-max = 19125
server.miner-fees.min-relay-fee = 510
server.test-mode = false
server.request-timeout = 20000
......@@ -55,6 +50,12 @@ server.export.mixs.filename = mixs.csv
server.export.activity.directory = ${server.export.directory}
server.export.activity.filename = activity.csv
# default pool fees
server.miner-fees.miner-fee-min = 170
server.miner-fees.miner-fee-cap = 9500
server.miner-fees.miner-fee-max = 19125
server.miner-fees.min-relay-fee = 510
# pool 0
server.pools[0].id = 0.5btc
server.pools[0].denomination = 50000000
......@@ -62,6 +63,7 @@ server.pools[0].fee-value = 2500000
server.pools[0].must-mix-min = 1
server.pools[0].liquidity-min = 1
server.pools[0].anonymity-set = 1
server.pools[0].tx0-max-outputs = 70
# pool 1
server.pools[1].id = 0.1btc
......@@ -70,6 +72,7 @@ server.pools[1].fee-value = 500000
server.pools[1].must-mix-min = 1
server.pools[1].liquidity-min = 1
server.pools[1].anonymity-set = 1
server.pools[1].tx0-max-outputs = 70
# pool 2
server.pools[2].id = 0.01btc
......@@ -78,6 +81,7 @@ server.pools[2].fee-value = 50000
server.pools[2].must-mix-min = 1
server.pools[2].liquidity-min = 1
server.pools[2].anonymity-set = 1
server.pools[2].tx0-max-outputs = 70
management.endpoints.jmx.exposure.exclude=*
management.endpoints.web.exposure.include=prometheus
......
......@@ -57,6 +57,7 @@
<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/>
Tx0 max outputs: <span th:text="${pool.tx0MaxOutputs}" />
</td>
</tr>
<tr>
......
......@@ -178,6 +178,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
pool.setMinAnonymitySet(1);
pool.setMixAnonymitySet(2);
pool.setMinMustMix(1);
pool.setTx0MaxOutputs(70);
byte[] feePayload = Utils.feePayloadShortToBytes(SCODE_FOO_PAYLOAD); // valid feePayload
String feePaymentCode = feeValidationService.getFeePaymentCode();
......@@ -185,7 +186,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
int feeIndex = 123456;
Tx0Data tx0Data = new Tx0Data(feePaymentCode, 0, 1111, 100, feePayload, feeAddress, feeIndex);
Tx0Preview tx0Preview = new Tx0Preview(tx0Data, 2, 2 * 4, 2, 1000102, 94998479, 4);
Tx0Preview tx0Preview = new Tx0Preview(pool, tx0Data, 2, 2 * 4, 2, 1, 1, 1000102, 94998479, 4);
Tx0 tx0 =
new Tx0Service(whirlpoolWalletConfig)
.tx0(
......@@ -234,6 +235,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
pool.setMinAnonymitySet(1);
pool.setMixAnonymitySet(2);
pool.setMinMustMix(1);
pool.setTx0MaxOutputs(70);
List<Pool> poolItems = new ArrayList<>();
poolItems.add(pool);
......@@ -244,7 +246,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
Tx0Data tx0Data =
new Tx0Data(feePaymentCode, 0, FEES_VALID, 0, feePayload, feeAddress, feeIndex);
Tx0Preview tx0Preview = new Tx0Preview(tx0Data, 2, 2 * 4, 2, 1000102, 94024590, 4);
Tx0Preview tx0Preview = new Tx0Preview(pool, tx0Data, 2, 2 * 4, 2, 1, 1, 1000102, 94024590, 4);
Tx0 tx0 =
new Tx0Service(whirlpoolWalletConfig)
......@@ -310,6 +312,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
pool.setMinAnonymitySet(1);
pool.setMixAnonymitySet(2);
pool.setMinMustMix(1);
pool.setTx0MaxOutputs(70);
List<Pool> poolItems = new ArrayList<>();
poolItems.add(pool);
......@@ -321,7 +324,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
Tx0Data tx0Data =
new Tx0Data(feePaymentCode, FEES_VALID, 0, 0, feePayload, feeAddress, feeIndex);
Tx0Preview tx0Preview = new Tx0Preview(tx0Data, 2, 2 * 4, 2, 1000102, 94024590, 4);
Tx0Preview tx0Preview = new Tx0Preview(pool, tx0Data, 2, 2 * 4, 2, 1, 1, 1000102, 94024590, 4);
Tx0 tx0 =
new Tx0Service(whirlpoolWalletConfig)
......@@ -371,6 +374,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
pool.setMinAnonymitySet(1);
pool.setMixAnonymitySet(2);
pool.setMinMustMix(1);
pool.setTx0MaxOutputs(70);
List<Pool> poolItems = new ArrayList<>();
poolItems.add(pool);
......@@ -382,7 +386,7 @@ public class FeeValidationServiceTest extends AbstractIntegrationTest {
Tx0Data tx0Data =
new Tx0Data(feePaymentCode, FEES_VALID, 0, 0, feePayload, feeAddress, feeIndex);
Tx0Preview tx0Preview = new Tx0Preview(tx0Data, 2, 2 * 4, 2, 1000102, 94024590, 4);
Tx0Preview tx0Preview = new Tx0Preview(pool, tx0Data, 2, 2 * 4, 2, 1, 1, 1000102, 94024590, 4);
Tx0 tx0 =
new Tx0Service(whirlpoolWalletConfig)
......
......@@ -13,11 +13,6 @@ spring.datasource.password=sa
server.samourai-fees.secret-wallet.words = all all all all all all all all all all all all
server.samourai-fees.secret-wallet.passphrase = whirlpool
server.miner-fees.miner-fee-min = 102
server.miner-fees.miner-fee-cap = 8000
server.miner-fees.miner-fee-max = 10000
server.miner-fees.min-relay-fee = 510
server.register-input.confirm-interval = 10
server.test-mode = false
......@@ -30,12 +25,19 @@ server.rpc-client.user = zeroleak
server.rpc-client.password = 833b09863f0ef98435382dfbe942352551124%e5316623659e3ba8__59bb911d562
server.rpc-client.mock-tx-broadcast = false
# default pool fees
server.miner-fees.miner-fee-min = 102
server.miner-fees.miner-fee-cap = 8000
server.miner-fees.miner-fee-max = 10000
server.miner-fees.min-relay-fee = 510
# pool 0
server.pools[0].id = 0.5btc
server.pools[0].denomination = 50000000
server.pools[0].must-mix-min = 1
server.pools[0].liquidity-min = 1
server.pools[0].anonymity-set = 2
server.pools[0].tx0-max-outputs = 70
# pool 1
server.pools[1].id = 0.1btc
......@@ -43,6 +45,7 @@ server.pools[1].denomination = 10000000
server.pools[1].must-mix-min = 1
server.pools[1].liquidity-min = 1
server.pools[1].anonymity-set = 2
server.pools[1].tx0-max-outputs = 70
# pool 2
server.pools[2].id = 0.01btc
......@@ -50,6 +53,7 @@ server.pools[2].denomination = 1000000
server.pools[2].must-mix-min = 1
server.pools[2].liquidity-min = 1
server.pools[2].anonymity-set = 2
server.pools[2].tx0-max-outputs = 70
# pool test
server.pools[3].id = 1btc
......@@ -57,3 +61,4 @@ server.pools[3].denomination = 100000000
server.pools[3].must-mix-min = 1
server.pools[3].liquidity-min = 1
server.pools[3].anonymity-set = 2
server.pools[3].tx0-max-outputs = 70
......@@ -19,22 +19,24 @@ server.ban.expiration = 1000
server.samourai-fees.secret-wallet.words = all all all all all all all all all all all all
server.samourai-fees.secret-wallet.passphrase = whirlpool
server.miner-fees.miner-fee-min = 102
server.miner-fees.miner-fee-cap = 8000
server.miner-fees.miner-fee-max = 10000
server.miner-fees.min-relay-fee = 510
server.register-input.confirm-interval = 2
server.test-mode = false
server.export.directory = /tmp
# default pool fees
server.miner-fees.miner-fee-min = 102
server.miner-fees.miner-fee-cap = 8000
server.miner-fees.miner-fee-max = 10000
server.miner-fees.min-relay-fee = 510
# pool 0
server.pools[0].id = 0.5btc
server.pools[0].denomination = 50000000
server.pools[0].must-mix-min = 1
server.pools[0].liquidity-min = 1
server.pools[0].anonymity-set = 2
server.pools[0].tx0-max-outputs = 70
# pool 1
server.pools[1].id = 0.1btc
......@@ -42,6 +44,7 @@ server.pools[1].denomination = 10000000
server.pools[1].must-mix-min = 1
server.pools[1].liquidity-min = 1
server.pools[1].anonymity-set = 2
server.pools[1].tx0-max-outputs = 70
# pool 2
server.pools[2].id = 0.01btc
......@@ -49,3 +52,4 @@ server.pools[2].denomination = 1000000
server.pools[2].must-mix-min = 1
server.pools[2].liquidity-min = 1
server.pools[2].anonymity-set = 2
server.pools[2].tx0-max-outputs = 70
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