Commit 9a0eeeda authored by zeroleak's avatar zeroleak
Browse files

remove mixsTarget selection to increase mix privacy

parent a7223cf2
......@@ -75,8 +75,6 @@ Response:
"progressLabel":"CONNECTING",
"poolId":"0.01btc",
"priority":5,
"mixsTarget":null,
"mixsTargetOrDefault":1,
"mixsDone":0,
"message":" - [MIX 1/1] ▮▮▮▮▮▯▯▯▯▯ (5/10) CONFIRMED_INPUT : joined a mix!",
"error":null,
......@@ -124,11 +122,9 @@ Parameters:
Payload:
* poolId: id of pool to join
* mixsTarget: mixs limit (0 for unlimited)
```
{
poolId: "0.01btc",
mixsTarget: 0
poolId: "0.01btc"
}
```
......@@ -139,15 +135,16 @@ Response:
}
```
### Tx0 preview ```POST /rest/utxos/{hash}:{index}/tx0Preview```
Parameters:
* hash, index: utxo to spend for tx0
### Tx0 preview ```POST /rest/tx0/preview```
Payload:
* inputs {hash, index} (mandatory): utxos to spend for tx0
* feeTarget (mandatory): fee target for tx0
* poolId (optional): override utxo's poolId
```
{
inputs: [
{hash:"c7f456d5ff002faa89dadec01cc5eb98bb00fdefb92031890324ec127f9d1541", index:5}
],
feeTarget: "BLOCKS_4",
poolId: "0.01btc"
}
......@@ -157,23 +154,22 @@ Payload:
Response:
```
{
"txid":"aa079c0323349f4abf3fb793bf2ed1ce1e11c53cd22aeced3554872033bfa722"
}
```
### Tx0 ```POST /rest/utxos/{hash}:{index}/tx0```
Parameters:
* hash, index: utxo to spend for tx0
### Tx0 ```POST /rest/tx0```
Payload:
* inputs {hash, index} (mandatory): utxos to spend for tx0
* feeTarget (mandatory): fee target for tx0
* poolId (optional): override utxo's poolId
* mixsTarget (optional): override utxo's mixsTarget
```
{
inputs: [
{hash:"c7f456d5ff002faa89dadec01cc5eb98bb00fdefb92031890324ec127f9d1541", index:5}
],
feeTarget: "BLOCKS_4",
poolId: "0.01btc",
mixsTarget: 3
poolId: "0.01btc"
}
```
......
......@@ -16,7 +16,6 @@ Default configuration is [../src/main/resources/application.properties].
| cli.tor | false | Enable Tor |
| cli.dojo.enabled | false | Enable Dojo as wallet backend |
| cli.scode | - | SCODE for discount Whirlpool fees |
| cli.mix.mixsTarget | 5 | Mixs limit per UTXO (0 for unlimited) |
| cli.mix.autoMix | true | Automatically (re)mix premix & postmix. When disabled, each utxo must be mixed manually. |
......@@ -88,7 +87,7 @@ You can configure your own cert:
| cli.tx0MinConfirmations | 0 | Confirmations required for TX0 |
| cli.mix.clients | 5 | Max simultaneous mixing clients |
| cli.mix.clientsPerPool | 1 | Max simultaneous mixing clients per pool |
| cli.mix.tx0MaxOutputs | 0 | Max premixs to create per TX0 (0 for unlimited) |
| cli.mix.tx0MaxOutputs | 0 | Max premixs to create per TX0 (0 for max = 70) |
| cli.mix.clientDelay | 15 | Connecting delay (seconds) between each mixing client |
| cli.mix.tx0Delay | 30 | Delay (seconds) between each tx0 (when --auto-tx0) |
| cli.seedAppendPassphrase | *generated on --init* | Use passphrase as additional seed word (always true for wallets created with SW, may be false for external wallets imported into SW) |
......
......@@ -15,7 +15,7 @@ You can run CLI in loop mode on testnet to generate liquidity on testnet server:
- mix while possible
- consolidate wallet when PREMIX is empty and start again
```
--clients=5 --auto-tx0=0.01btc --tx0-max-outputs=15 --mixs-target=100 --scode=
--clients=5 --auto-tx0=0.01btc --tx0-max-outputs=15 --scode=
```
Adjust mixing rate with ```cli.mix.clientDelay = 60```
......
......@@ -32,7 +32,6 @@ public class ApplicationArgs {
private static final String ARG_API_KEY = "api-key";
public static final String ARG_INIT = "init";
private static final String ARG_AUTHENTICATE = "authenticate";
private static final String ARG_MIXS_TARGET = "mixs-target";
private static final String ARG_DUMP_PAYLOAD = "dump-payload";
private static final String ARG_RESYNC = "resync";
......@@ -92,11 +91,6 @@ public class ApplicationArgs {
cliConfig.setApiKey(value);
}
valueInt = optionalInt(ARG_MIXS_TARGET);
if (valueInt != null) {
cliConfig.getMix().setMixsTarget(valueInt);
}
valueBool = optionalBoolean(ARG_RESYNC);
if (valueBool != null) {
cliConfig.setResync(valueBool);
......
......@@ -22,7 +22,7 @@ public class MixController extends AbstractRestController {
checkHeaders(headers);
WhirlpoolWallet whirlpoolWallet = cliWalletService.getSessionWallet();
MixingState mixingState = whirlpoolWallet.getMixingState();
return new ApiWalletStateResponse(mixingState, whirlpoolWallet.getConfig().getMixsTarget());
return new ApiWalletStateResponse(mixingState);
}
@RequestMapping(value = CliApiEndpoint.REST_MIX_START, method = RequestMethod.POST)
......
......@@ -3,6 +3,7 @@ package com.samourai.whirlpool.cli.api.controllers.utxo;
import com.samourai.whirlpool.cli.api.controllers.AbstractRestController;
import com.samourai.whirlpool.cli.api.protocol.CliApiEndpoint;
import com.samourai.whirlpool.cli.api.protocol.beans.ApiUtxo;
import com.samourai.whirlpool.cli.api.protocol.beans.ApiUtxoRef;
import com.samourai.whirlpool.cli.api.protocol.rest.*;
import com.samourai.whirlpool.cli.services.CliWalletService;
import com.samourai.whirlpool.client.exception.NotifiableException;
......@@ -12,7 +13,8 @@ import com.samourai.whirlpool.client.tx0.Tx0Preview;
import com.samourai.whirlpool.client.wallet.WhirlpoolWallet;
import com.samourai.whirlpool.client.wallet.beans.WhirlpoolUtxo;
import com.samourai.whirlpool.client.whirlpool.beans.Pool;
import java8.util.Lists;
import java.util.LinkedList;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
......@@ -32,6 +34,19 @@ public class UtxoController extends AbstractRestController {
return whirlpoolUtxo;
}
private List<WhirlpoolUtxo> findUtxos(ApiUtxoRef[] utxoRefs) throws Exception {
List<WhirlpoolUtxo> whirlpoolUtos = new LinkedList<>();
for (ApiUtxoRef utxoRef : utxoRefs) {
// find utxo
WhirlpoolUtxo whirlpoolUtxo = findUtxo(utxoRef.getHash(), utxoRef.getIndex());
if (whirlpoolUtxo == null) {
throw new NotifiableException("Utxo not found: " + utxoRef.toString());
}
whirlpoolUtos.add(whirlpoolUtxo);
}
return whirlpoolUtos;
}
@RequestMapping(value = CliApiEndpoint.REST_UTXO_CONFIGURE, method = RequestMethod.POST)
public ApiUtxo configureUtxo(
@RequestHeader HttpHeaders headers,
......@@ -48,25 +63,18 @@ public class UtxoController extends AbstractRestController {
// configure pool
whirlpoolWallet.setPool(whirlpoolUtxo, payload.poolId);
// configure mixsTarget
whirlpoolWallet.setMixsTarget(whirlpoolUtxo, payload.mixsTarget);
int mixsTargetMin = whirlpoolWallet.getConfig().getMixsTarget();
ApiUtxo apiUtxo = new ApiUtxo(whirlpoolUtxo, mixsTargetMin);
ApiUtxo apiUtxo = new ApiUtxo(whirlpoolUtxo);
return apiUtxo;
}
@RequestMapping(value = CliApiEndpoint.REST_UTXO_TX0_PREVIEW, method = RequestMethod.POST)
public ApiTx0PreviewResponse tx0Preview(
@RequestHeader HttpHeaders headers,
@PathVariable("hash") String utxoHash,
@PathVariable("index") int utxoIndex,
@Valid @RequestBody ApiTx0PreviewRequest payload)
@RequestHeader HttpHeaders headers, @Valid @RequestBody ApiTx0PreviewRequest payload)
throws Exception {
checkHeaders(headers);
// find utxo
WhirlpoolUtxo whirlpoolUtxo = findUtxo(utxoHash, utxoIndex);
List<WhirlpoolUtxo> whirlpoolUtxos = findUtxos(payload.inputs);
WhirlpoolWallet whirlpoolWallet = cliWalletService.getSessionWallet();
Pool pool = whirlpoolWallet.getPoolSupplier().findPoolById(payload.poolId);
......@@ -77,28 +85,20 @@ public class UtxoController extends AbstractRestController {
// tx0 preview
Tx0Config tx0Config = whirlpoolWallet.getTx0Config();
Tx0Preview tx0Preview =
whirlpoolWallet.tx0Preview(Lists.of(whirlpoolUtxo), pool, tx0Config, payload.feeTarget);
whirlpoolWallet.tx0Preview(whirlpoolUtxos, pool, tx0Config, payload.feeTarget);
return new ApiTx0PreviewResponse(tx0Preview);
}
@RequestMapping(value = CliApiEndpoint.REST_UTXO_TX0, method = RequestMethod.POST)
public ApiTx0Response tx0(
@RequestHeader HttpHeaders headers,
@PathVariable("hash") String utxoHash,
@PathVariable("index") int utxoIndex,
@Valid @RequestBody ApiTx0Request payload)
@RequestHeader HttpHeaders headers, @Valid @RequestBody ApiTx0Request payload)
throws Exception {
checkHeaders(headers);
// find utxo
WhirlpoolUtxo whirlpoolUtxo = findUtxo(utxoHash, utxoIndex);
List<WhirlpoolUtxo> whirlpoolUtxos = findUtxos(payload.inputs);
WhirlpoolWallet whirlpoolWallet = cliWalletService.getSessionWallet();
// override utxo settings
if (payload.mixsTarget != null && payload.mixsTarget > 0) {
whirlpoolWallet.setMixsTarget(whirlpoolUtxo, payload.mixsTarget);
}
Pool pool = whirlpoolWallet.getPoolSupplier().findPoolById(payload.poolId);
if (pool == null) {
throw new NotifiableException("poolId is not valid");
......@@ -106,7 +106,7 @@ public class UtxoController extends AbstractRestController {
// tx0
Tx0Config tx0Config = whirlpoolWallet.getTx0Config();
Tx0 tx0 = whirlpoolWallet.tx0(Lists.of(whirlpoolUtxo), pool, payload.feeTarget, tx0Config);
Tx0 tx0 = whirlpoolWallet.tx0(whirlpoolUtxos, pool, payload.feeTarget, tx0Config);
return new ApiTx0Response(tx0);
}
......
......@@ -21,9 +21,8 @@ public class CliApiEndpoint {
public static final String REST_UTXOS = REST_PREFIX + "utxos";
public static final String REST_UTXO_CONFIGURE = REST_PREFIX + "utxos/{hash}:{index}";
public static final String REST_UTXO_TX0 = REST_PREFIX + "utxos/{hash}:{index}/tx0";
public static final String REST_UTXO_TX0_PREVIEW =
REST_PREFIX + "utxos/{hash}:{index}/tx0Preview";
public static final String REST_UTXO_TX0 = REST_PREFIX + "tx0";
public static final String REST_UTXO_TX0_PREVIEW = REST_PREFIX + "tx0/preview";
public static final String REST_UTXO_STARTMIX = REST_PREFIX + "utxos/{hash}:{index}/startMix";
public static final String REST_UTXO_STOPMIX = REST_PREFIX + "utxos/{hash}:{index}/stopMix";
......
......@@ -30,7 +30,6 @@ public class ApiCliConfig {
private static final String KEY_MIX_CLIENT_DELAY = "cli.mix.clientDelay";
private static final String KEY_MIX_TX0_MAX_OUTPUTS = "cli.mix.tx0MaxOutputs";
private static final String KEY_MIX_AUTO_MIX = "cli.mix.autoMix";
private static final String KEY_MIX_MIXS_TARGET = "cli.mix.mixsTarget";
public static final String KEY_API_HTTP_ENABLE = "cli.api.http-enable";
public ApiCliConfig() {}
......@@ -128,7 +127,6 @@ public class ApiCliConfig {
private Integer clientDelay;
private Integer tx0MaxOutputs;
private Boolean autoMix;
private Integer mixsTarget;
public ApiMixConfig() {}
......@@ -137,7 +135,6 @@ public class ApiCliConfig {
this.clientDelay = mixConfig.getClientDelay();
this.tx0MaxOutputs = mixConfig.getTx0MaxOutputs();
this.autoMix = mixConfig.isAutoMix();
this.mixsTarget = mixConfig.getMixsTarget();
}
public void toProperties(Properties props) throws NotifiableException {
......@@ -162,12 +159,6 @@ public class ApiCliConfig {
if (autoMix != null) {
props.put(KEY_MIX_AUTO_MIX, Boolean.toString(autoMix));
}
if (mixsTarget != null) {
if (mixsTarget < 1) {
throw new NotifiableException("mix.mixTargets should be > 0");
}
props.put(KEY_MIX_MIXS_TARGET, Integer.toString(mixsTarget));
}
}
public Integer getClientsPerPool() {
......@@ -201,13 +192,5 @@ public class ApiCliConfig {
public void setAutoMix(Boolean autoMix) {
this.autoMix = autoMix;
}
public Integer getMixsTarget() {
return mixsTarget;
}
public void setMixsTarget(Integer mixsTarget) {
this.mixsTarget = mixsTarget;
}
}
}
......@@ -18,14 +18,12 @@ public class ApiUtxo {
private MixableStatus mixableStatus;
private Integer progressPercent;
private String poolId;
private Integer mixsTarget;
private Integer mixsTargetOrDefault;
private int mixsDone;
private String message;
private String error;
private Long lastActivityElapsed;
public ApiUtxo(WhirlpoolUtxo whirlpoolUtxo, int mixsTargetMin) {
public ApiUtxo(WhirlpoolUtxo whirlpoolUtxo) {
UnspentOutput utxo = whirlpoolUtxo.getUtxo();
this.hash = utxo.tx_hash;
this.index = utxo.tx_output_n;
......@@ -43,8 +41,6 @@ public class ApiUtxo {
this.progressPercent =
utxoState.getMixProgress() != null ? utxoState.getMixProgress().getProgressPercent() : null;
this.poolId = whirlpoolUtxo.getPoolId();
this.mixsTarget = whirlpoolUtxo.getMixsTarget();
this.mixsTargetOrDefault = whirlpoolUtxo.getMixsTargetOrDefault(mixsTargetMin);
this.mixsDone = whirlpoolUtxo.getMixsDone();
this.message = utxoState.getMessage();
this.error = utxoState.getError();
......@@ -102,14 +98,6 @@ public class ApiUtxo {
return poolId;
}
public Integer getMixsTarget() {
return mixsTarget;
}
public Integer getMixsTargetOrDefault() {
return mixsTargetOrDefault;
}
public int getMixsDone() {
return mixsDone;
}
......
package com.samourai.whirlpool.cli.api.protocol.beans;
public class ApiUtxoRef {
private String hash;
private int index;
public ApiUtxoRef(String hash, int index) {
this.hash = hash;
this.index = index;
}
public String getHash() {
return hash;
}
public int getIndex() {
return index;
}
}
......@@ -11,15 +11,12 @@ public class ApiWallet {
private String zpub;
public ApiWallet(
Collection<WhirlpoolUtxo> whirlpoolUtxos,
String zpub,
Comparator<WhirlpoolUtxo> comparator,
int mixsTargetMin) {
Collection<WhirlpoolUtxo> whirlpoolUtxos, String zpub, Comparator<WhirlpoolUtxo> comparator) {
this.utxos =
whirlpoolUtxos
.stream()
.sorted(comparator)
.map(whirlpoolUtxo -> new ApiUtxo(whirlpoolUtxo, mixsTargetMin))
.map(whirlpoolUtxo -> new ApiUtxo(whirlpoolUtxo))
.collect(Collectors.toList());
this.balance =
whirlpoolUtxos.stream().mapToLong(whirlpoolUtxo -> whirlpoolUtxo.getUtxo().value).sum();
......
package com.samourai.whirlpool.cli.api.protocol.rest;
import com.samourai.whirlpool.cli.api.protocol.beans.ApiUtxoRef;
import com.samourai.whirlpool.client.wallet.beans.Tx0FeeTarget;
import javax.validation.constraints.NotNull;
public class ApiTx0PreviewRequest {
@NotNull public ApiUtxoRef[] inputs;
@NotNull public Tx0FeeTarget feeTarget;
@NotNull public String poolId;
......
package com.samourai.whirlpool.cli.api.protocol.rest;
public class ApiTx0Request extends ApiTx0PreviewRequest {
public Integer mixsTarget;
public ApiTx0Request() {}
}
......@@ -2,7 +2,6 @@ package com.samourai.whirlpool.cli.api.protocol.rest;
public class ApiUtxoConfigureRequest {
public String poolId;
public int mixsTarget;
public ApiUtxoConfigureRequest() {}
}
......@@ -12,7 +12,7 @@ public class ApiWalletStateResponse {
private int nbQueued;
private Collection<ApiUtxo> threads;
public ApiWalletStateResponse(MixingState mixingState, int mixsTargetMin) {
public ApiWalletStateResponse(MixingState mixingState) {
this.started = mixingState.isStarted();
this.nbMixing = mixingState.getNbMixing();
this.nbQueued = mixingState.getNbQueued();
......@@ -20,7 +20,7 @@ public class ApiWalletStateResponse {
mixingState
.getUtxosMixing()
.stream()
.map(whirlpoolUtxo -> new ApiUtxo(whirlpoolUtxo, mixsTargetMin))
.map(whirlpoolUtxo -> new ApiUtxo(whirlpoolUtxo))
.collect(Collectors.toList());
}
......
......@@ -52,8 +52,7 @@ public class ApiWalletUtxosResponse {
Comparator<WhirlpoolUtxo> comparator) {
Collection<WhirlpoolUtxo> utxos = whirlpoolWallet.getUtxoSupplier().findUtxos(account);
String zpub = whirlpoolWallet.getWalletSupplier().getWallet(account).getZpub();
int mixsTargetMin = whirlpoolWallet.getConfig().getMixsTarget();
return new ApiWallet(utxos, zpub, comparator, mixsTargetMin);
return new ApiWallet(utxos, zpub, comparator);
}
public ApiWallet getDeposit() {
......
......@@ -200,7 +200,6 @@ public abstract class CliConfigFile {
@NotEmpty private int tx0Delay;
@NotEmpty private int tx0MaxOutputs;
@NotEmpty private boolean autoMix;
@NotEmpty private int mixsTarget;
private Map<String, Long> overspend;
public MixConfig() {}
......@@ -213,7 +212,6 @@ public abstract class CliConfigFile {
this.tx0Delay = copy.tx0Delay;
this.tx0MaxOutputs = copy.tx0MaxOutputs;
this.autoMix = copy.autoMix;
this.mixsTarget = copy.mixsTarget;
this.overspend = copy.overspend != null ? new HashMap<>(copy.overspend) : null;
}
......@@ -274,14 +272,6 @@ public abstract class CliConfigFile {
this.autoMix = autoMix;
}
public int getMixsTarget() {
return mixsTarget;
}
public void setMixsTarget(int mixsTarget) {
this.mixsTarget = mixsTarget;
}
public Map<String, Long> getOverspend() {
return overspend;
}
......@@ -299,7 +289,6 @@ public abstract class CliConfigFile {
configInfo.put("cli/mix/tx0Delay", Integer.toString(tx0Delay));
configInfo.put("cli/mix/tx0MaxOutputs", Integer.toString(tx0MaxOutputs));
configInfo.put("cli/mix/autoMix", Boolean.toString(autoMix));
configInfo.put("cli/mix/mixsTarget", Integer.toString(mixsTarget));
configInfo.put("cli/mix/overspend", overspend != null ? overspend.toString() : "null");
return configInfo;
}
......@@ -538,7 +527,6 @@ public abstract class CliConfigFile {
config.setTx0Delay(mix.getTx0Delay());
config.setTx0MaxOutputs(mix.getTx0MaxOutputs());
config.setAutoMix(mix.isAutoMix());
config.setMixsTarget(mix.getMixsTarget());
config.setOverspend(mix.getOverspend());
config.setResyncOnFirstRun(true);
......
......@@ -69,7 +69,7 @@ public class CliStatusInteractiveOrchestrator extends AbstractOrchestrator {
log.info("⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿");
log.info("⣿ MIXING THREADS:");
String lineFormat = "| %8s | %25s | %8s | %10s | %10s | %8s | %68s | %14s | %8s | %8s |\n";
String lineFormat = "| %8s | %25s | %8s | %10s | %10s | %8s | %68s | %14s | %8s | %6s |\n";
StringBuilder sb = new StringBuilder();
sb.append(
String.format(
......@@ -93,8 +93,6 @@ public class CliStatusInteractiveOrchestrator extends AbstractOrchestrator {
String since = mixProgress != null ? ((now - mixProgress.getSince()) / 1000) + "s" : "";
UnspentOutput o = whirlpoolUtxo.getUtxo();
String utxo = o.tx_hash + ":" + o.tx_output_n;
int mixsTargetMin = cliConfig.getMix().getMixsTarget();
int mixsTargetOrDefault = whirlpoolUtxo.getMixsTargetOrDefault(mixsTargetMin);
sb.append(
String.format(
lineFormat,
......@@ -107,11 +105,7 @@ public class CliStatusInteractiveOrchestrator extends AbstractOrchestrator {
utxo,
o.getPath(),
whirlpoolUtxo.getPoolId() != null ? whirlpoolUtxo.getPoolId() : "-",
whirlpoolUtxo.getMixsDone()
+ "/"
+ (mixsTargetOrDefault == WhirlpoolUtxoConfig.MIXS_TARGET_UNLIMITED
? "∞"
: mixsTargetOrDefault)));
whirlpoolUtxo.getMixsDone()));
i++;
}
......@@ -158,7 +152,7 @@ public class CliStatusInteractiveOrchestrator extends AbstractOrchestrator {
try {
log.info("⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿");
log.info("⣿ " + account.name() + " UTXOS:");
ClientUtils.logWhirlpoolUtxos(utxos, cliConfig.getMix().getMixsTarget());
ClientUtils.logWhirlpoolUtxos(utxos);
} catch (Exception e) {
log.error("", e);
......
......@@ -41,4 +41,3 @@ cli.mix.tx0MaxOutputs = 0
cli.mix.clientDelay = 15
cli.mix.tx0Delay = 30
cli.mix.autoMix = true
cli.mix.mixsTarget = 5
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