Skip to content

Commit efb3392

Browse files
authored
simnet: Add per-match address tests and README. (#3562)
* simnet: Expand trade tests and fix multi-asset harness issues. Add four new simnet trade tests exercising per-match swap address protocol: notakeraddr, nomakeraddr, notakerredeem, and missedcpaddr. Enhance trade monitoring to verify per-match SwapAddr uniqueness and CounterPartyAddr population. Add sendFilter to tConn and withRequestFilter/withSendFilter helpers for cleaner filter lifecycle. Fix polygon simnet FinalizeConfs (was 64, now 2 on simnet) so polygon redeems confirm within the test timeout. Fix orderstatus test Badger DB lock by disabling wallets after disconnect to prevent background bond maintenance from reconnecting old wallets. Skip EVM balance assertions in missedcpaddr test (same rationale as simpleTradeTest). Clamp test order rates to the market minimum rate so markets like zec_btc with high minimum rates don't reject orders. Bump ZEC simnet maxFeeRate from 200 to 10000 to match the wallet's ZIP-317 fee rate. Add new markets (LTC/DASH, DOGE/POLYGON, BCH/ETH, FIRO/BTC) to enable running more test pairs in parallel without wallet conflicts. Switch EVM harness connections from IPC to websocket endpoints in both simnet trade tests and loadbot. Add build commit/dirty logging to the run script. Add README for simnet-trade-tests. Document per-match address design rationale in server/swap/swap.go and client/core/trade.go. * zec: Fix refund fee calculation for ZIP-317 compliance. The refund was passing the per-action fee rate (5000 zats) as the absolute fee, but a refund tx has 2 logical actions under ZIP-317, requiring 10,000 zats. Calculate the proper fee using TxFeesZIP317 based on actual input/output sizes. * btc: Retry block tx lookup in FindRedemption for multi-node setups. In multi-node configurations (e.g. DASH), there can be a delay between one node reporting a transaction in a block via gettransaction and that block's full data being available from getblock on a different node. Add a retry loop (up to 10 attempts with 1s delay) in checkRedemptionBlockDetails to handle this race condition. * multi: DRY up v1 token gas values and fix simnet. Define tokenV1Gases once per chain (eth, polygon, base) from the measured usdt mainnet values and reference it everywhere instead of duplicating the same gas values across every token and network. Also fix simnet v1 token gas estimates that were either empty or incorrectly measured from ETH native swaps instead of token swaps. * ui: Fix wallet unlock affecting all networks for same ticker. openWallet was iterating over all networkAssets sharing the same normalized ticker and unlocking every one. This meant unlocking ETH on Ethereum would also unlock ETH on Base. The lock side already operated on individual assets. Align unlock to match. * ui: Show disabled state for individually disabled token wallets. The per-network wallet row and actions modal only checked the parent wallet's disabled state. A token wallet disabled independently (e.g. polygon.eth via RPC) would appear enabled in the UI with no way to re-enable it. Now both the status icon and the Enable action check the token wallet's own disabled flag.
1 parent 7fa27f9 commit efb3392

File tree

16 files changed

+1139
-402
lines changed

16 files changed

+1139
-402
lines changed

client/asset/btc/redemption_finder.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,28 @@ func (r *RedemptionFinder) checkRedemptionBlockDetails(outPt OutPoint, blockHash
191191
}
192192

193193
var tx *wire.MsgTx
194-
out:
195-
for _, iTx := range blk.Transactions {
196-
if *r.hashTx(iTx) == outPt.TxHash {
197-
tx = iTx
198-
break out
194+
for try := 0; ; try++ {
195+
for _, iTx := range blk.Transactions {
196+
if *r.hashTx(iTx) == outPt.TxHash {
197+
tx = iTx
198+
break
199+
}
200+
}
201+
if tx != nil {
202+
break
203+
}
204+
if try >= 10 {
205+
return 0, fmt.Errorf("transaction %s not found in block %s after retries", outPt.TxHash, blockHash)
206+
}
207+
// Multi-node setups can have a delay between one node reporting
208+
// a transaction in a block and that block's full data being
209+
// available from getblock. Retry with a short delay.
210+
r.log.Debugf("Transaction %s not yet found in block %s (attempt %d), retrying...", outPt.TxHash, blockHash, try+1)
211+
time.Sleep(time.Second)
212+
blk, err = r.getBlock(*blockHash)
213+
if err != nil {
214+
return 0, fmt.Errorf("error re-retrieving block %s: %w", blockHash, err)
199215
}
200-
}
201-
if tx == nil {
202-
return 0, fmt.Errorf("transaction %s not found in block %s", outPt.TxHash, blockHash)
203216
}
204217
if uint32(len(tx.TxOut)) < outPt.Vout+1 {
205218
return 0, fmt.Errorf("no output %d in redemption transaction %s found in block %s", outPt.Vout, outPt.TxHash, blockHash)

client/asset/polygon/polygon.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ var (
9797
}
9898
)
9999

100+
func polygonFinalizeConfs(net dex.Network) uint64 {
101+
if net == dex.Simnet {
102+
return 2
103+
}
104+
return 64
105+
}
106+
100107
type Driver struct{}
101108

102109
// Open opens the Polygon exchange wallet. Start the wallet with its Run method.
@@ -149,7 +156,7 @@ func (d *Driver) Open(cfg *asset.WalletConfig, logger dex.Logger, net dex.Networ
149156
CompatData: &compat,
150157
VersionedGases: dexpolygon.VersionedGases,
151158
Tokens: dexpolygon.Tokens,
152-
FinalizeConfs: 64,
159+
FinalizeConfs: polygonFinalizeConfs(net),
153160
Logger: logger,
154161
BaseChainContracts: contracts,
155162
MultiBalAddress: dexpolygon.MultiBalanceAddresses[net],

client/asset/zec/zec.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,13 @@ func (w *zecWallet) Refund(ctx context.Context, coinID, contract dex.Bytes, feeR
20282028
if utxo == nil {
20292029
return nil, asset.CoinNotFoundError // spent
20302030
}
2031-
msgTx, err := w.refundTx(ctx, txHash, vout, contract, uint64(utxo.Value), nil, feeRate)
2031+
// Calculate ZIP-317 compliant fees for the refund tx. The feeRate
2032+
// parameter is per-action, but ZIP-317 requires fees based on logical
2033+
// actions derived from tx structure, not a simple rate.
2034+
var inputsSize uint64 = dexbtc.TxInOverhead + dexbtc.RefundSigScriptSize + 1
2035+
var outputsSize uint64 = dexbtc.P2PKHOutputSize + 1
2036+
refundFees := dexzec.TxFeesZIP317(inputsSize, outputsSize, 0, 0, 0, 0)
2037+
msgTx, err := w.refundTx(ctx, txHash, vout, contract, uint64(utxo.Value), nil, refundFees)
20322038
if err != nil {
20332039
return nil, fmt.Errorf("error creating refund tx: %w", err)
20342040
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Simnet Trade Tests
2+
3+
End-to-end integration tests that exercise real trades on simnet using asset
4+
harnesses. Two simulated DEX clients place orders, match, and settle (or fail
5+
to settle) across a variety of scenarios.
6+
7+
## Prerequisites
8+
9+
Start the asset harnesses for the pair you want to test, then start the dcrdex
10+
harness. For example, to test DCR-BTC:
11+
12+
```sh
13+
cd ~/dextest
14+
./dcr/harness.sh
15+
./btc/harness.sh
16+
./dcrdex/harness.sh
17+
```
18+
19+
The asset harnesses run background miners (`watch -n 15 ./mine-alpha 1`) by
20+
default. The trade tests mine their own blocks at specific points, so
21+
background mining can interfere with confirmation counting. Disable it by
22+
exporting `NOMINER=1` before starting each asset harness:
23+
24+
```sh
25+
export NOMINER=1
26+
./dcr/harness.sh
27+
./btc/harness.sh
28+
```
29+
30+
## Building
31+
32+
The tests require the `harness` build tag:
33+
34+
```sh
35+
go build -tags harness ./client/cmd/simnet-trade-tests/
36+
```
37+
38+
## Running
39+
40+
The easiest way is through the `run` script, which rebuilds with shortened swap
41+
lock times (3m taker, 6m maker) and selects the right node flags for each pair:
42+
43+
```sh
44+
./run dcrbtc
45+
```
46+
47+
Run `./run help` to see all pre-configured pairs and available flags.
48+
49+
### Pre-configured pairs
50+
51+
| Command | Market | Notes |
52+
| ------------------ | --------------- | ----------------------------- |
53+
| `dcrbtc` | DCR-BTC | RPC wallets |
54+
| `dcrspvbtc` | DCR-BTC | DCR SPV, BTC RPC |
55+
| `dcrbtcspv` | DCR-BTC | DCR RPC, BTC SPV |
56+
| `dcrbtcelectrum` | DCR-BTC | DCR RPC, BTC Electrum |
57+
| `bchdcr` | BCH-DCR | RPC wallets |
58+
| `bchspvdcr` | BCH-DCR | BCH SPV, DCR RPC |
59+
| `ltcdcr` | LTC-DCR | RPC wallets |
60+
| `ltcspvdcr` | LTC-DCR | LTC SPV, DCR RPC |
61+
| `ltcelectrumdcr` | LTC-DCR | LTC Electrum, DCR RPC |
62+
| `dcrdash` | DCR-DASH | RPC wallets |
63+
| `dcrdoge` | DCR-DOGE | RPC wallets |
64+
| `dcrdgb` | DCR-DGB | RPC wallets |
65+
| `dcreth` | DCR-ETH | DCR RPC, ETH native |
66+
| `dcrfiro` | DCR-FIRO | RPC wallets |
67+
| `dcrfiroelectrum` | DCR-FIRO | DCR RPC, FIRO Electrum |
68+
| `zecbtc` | ZEC-BTC | RPC wallets |
69+
| `dcrusdc` | DCR-USDC.ETH | ERC-20 token on Ethereum |
70+
| `polygondcr` | POLYGON-DCR | Polygon RPC, DCR RPC |
71+
| `dcrusdcpolygon` | DCR-USDC.POLYGON| ERC-20 token on Polygon |
72+
| `zclbtc` | ZCL-BTC | RPC wallets |
73+
74+
### Selecting tests
75+
76+
By default only the `success` test runs. Use `-t` to pick specific tests, or
77+
`--all` to run everything:
78+
79+
```sh
80+
./run dcrbtc -t success -t nomakerswap
81+
./run dcrbtc --all
82+
./run dcrbtc --all --except=orderstatus
83+
```
84+
85+
Available tests:
86+
87+
| Test | Description |
88+
| ---------------- | -------------------------------------------------------- |
89+
| `success` | Complete trade with swaps and redeems on both sides |
90+
| `nomakerswap` | Maker fails to send swap tx |
91+
| `notakerswap` | Taker fails to swap; refund after locktime |
92+
| `nomakerredeem` | Maker fails to redeem; both sides refund |
93+
| `makerghost` | Maker disappears after taker redeems; auto-redeem tested |
94+
| `orderstatus` | Order status recovery after client disconnection |
95+
| `resendpending` | Resending of pending trade requests |
96+
| `notakeraddr` | Taker omits per-match swap address; taker penalized |
97+
| `nomakeraddr` | Maker omits per-match swap address; maker penalized |
98+
| `notakerredeem` | Taker fails to redeem after maker redeems; taker penalty |
99+
| `missedcpaddr` | Counterparty address re-delivered after reconnect |
100+
101+
Each test runs twice by default, swapping which client is maker and which is
102+
taker. Pass `--runonce` to only run each test once.
103+
104+
### Other useful flags
105+
106+
```
107+
--debug Log at debug level
108+
--trace Log at trace level
109+
--color <color> Log color: green (default), white, blue, yellow, magenta, red
110+
--regasset <sym> Asset for bond registration (default: base asset)
111+
```
112+
113+
## Troubleshooting
114+
115+
- **"coin locked"** - The DEX hasn't revoked a previously failed match. Wait a
116+
few seconds and retry, or clear the dcrdex db and restart the dcrdex harness.
117+
- **"not enough to cover requested funds"** - Use the asset harness to send
118+
more funds to the affected wallet.
119+
- **Fee payment confirmation issues** - Restart the dcr harness then the dcrdex
120+
harness (stop dcrdex first).

client/cmd/simnet-trade-tests/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"decred.org/dcrdex/client/core"
1212
"decred.org/dcrdex/dex"
13+
dexbase "decred.org/dcrdex/dex/networks/base"
1314
dexeth "decred.org/dcrdex/dex/networks/eth"
1415
dexpolygon "decred.org/dcrdex/dex/networks/polygon"
1516
"github.com/fatih/color"
@@ -223,4 +224,5 @@ func (f *flagArray) Set(value string) error {
223224
func init() {
224225
dexeth.MaybeReadSimnetAddrs()
225226
dexpolygon.MaybeReadSimnetAddrs()
227+
dexbase.MaybeReadSimnetAddrs()
226228
}

client/cmd/simnet-trade-tests/run

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/bin/bash
22
set -e
33

4+
echo "Building simnet-trade-tests at commit $(git rev-parse --short HEAD) ($(git diff --stat --quiet 2>/dev/null && echo 'clean' || echo 'dirty'))"
5+
46
go build -tags harness -ldflags \
57
"-X 'decred.org/dcrdex/dex.testLockTimeTaker=3m' \
68
-X 'decred.org/dcrdex/dex.testLockTimeMaker=6m'"
@@ -28,11 +30,6 @@ case $1 in
2830
--regasset dcr ${@:2}
2931
;;
3032

31-
bchspvdcr)
32-
./simnet-trade-tests --base bch --quote dcr --quote1node trading1 --quote2node trading2 \
33-
--regasset dcr --base1type=spv ${@:2}
34-
;;
35-
3633
ltcdcr)
3734
./simnet-trade-tests --base ltc --quote dcr --quote1node trading1 --quote2node trading2 \
3835
--regasset dcr ${@:2}
@@ -66,6 +63,10 @@ case $1 in
6663
./simnet-trade-tests --base1node trading1 --base2node trading2 --quote eth ${@:2}
6764
;;
6865

66+
dcrspveth)
67+
./simnet-trade-tests --base1node trading1 --base2node trading2 --quote eth --base1type spv ${@:2}
68+
;;
69+
6970
dcrfiro)
7071
./simnet-trade-tests --base1node trading1 --base2node trading2 --quote firo ${@:2}
7172
;;
@@ -90,6 +91,67 @@ case $1 in
9091
./simnet-trade-tests --quote1node trading1 --quote2node trading2 --base usdc.polygon --quote dcr --regasset dcr ${@:2}
9192
;;
9293

94+
ethbtc)
95+
./simnet-trade-tests --base eth --quote btc --regasset btc ${@:2}
96+
;;
97+
98+
ltceth)
99+
./simnet-trade-tests --base ltc --quote eth --regasset ltc ${@:2}
100+
;;
101+
102+
bchpolygon)
103+
./simnet-trade-tests --base bch --quote polygon --regasset bch ${@:2}
104+
;;
105+
106+
ltcdash)
107+
./simnet-trade-tests --base ltc --quote dash --regasset ltc \
108+
--quote1node gamma --quote2node delta ${@:2}
109+
;;
110+
111+
dogepolygon)
112+
./simnet-trade-tests --base doge --quote polygon --regasset doge ${@:2}
113+
;;
114+
115+
bcheth)
116+
./simnet-trade-tests --base bch --quote eth --regasset bch ${@:2}
117+
;;
118+
119+
ltcspveth)
120+
./simnet-trade-tests --base ltc --quote eth --regasset ltc --base1type spv ${@:2}
121+
;;
122+
123+
firobtc)
124+
./simnet-trade-tests --base firo --quote btc --regasset btc ${@:2}
125+
;;
126+
127+
firobtcspv)
128+
./simnet-trade-tests --base firo --quote btc --regasset btc --quote1type spv ${@:2}
129+
;;
130+
131+
firodoge)
132+
./simnet-trade-tests --base firo --quote doge --regasset doge ${@:2}
133+
;;
134+
135+
btcusdceth)
136+
./simnet-trade-tests --base btc --quote usdc.eth --regasset btc ${@:2}
137+
;;
138+
139+
btcusdteth)
140+
./simnet-trade-tests --base btc --quote usdt.eth --regasset btc ${@:2}
141+
;;
142+
143+
ltcusdcbase)
144+
./simnet-trade-tests --base ltc --quote usdc.base --regasset ltc ${@:2}
145+
;;
146+
147+
dcrusdtpolygon)
148+
./simnet-trade-tests --base1node trading1 --base2node trading2 --quote usdt.polygon ${@:2}
149+
;;
150+
151+
dcrusdtbase)
152+
./simnet-trade-tests --base1node trading1 --base2node trading2 --quote usdt.base ${@:2}
153+
;;
154+
93155
zclbtc)
94156
./simnet-trade-tests --base zcl --quote btc --regasset btc ${@:2}
95157
;;
@@ -107,20 +169,35 @@ dcrspvbtc - Decred SPV wallet and Bitcoin RPC wallet on DCR-BTC
107169
dcrbtcspv - Decred RPC wallet and Bitcoin SPV wallet on DCR-BTC market
108170
dcrbtcelectrum - Decred RPC wallet and Bitcoin Electrum wallet on DCR-BTC market
109171
bchdcr - RPC wallets on BCH-DCR market
110-
bchspvdcr - Bitcoin Cash SPV wallet and Decred RPC Wallet on BCH-DCR market
111172
ltcdcr - RPC wallets on LTC-DCR market
112173
ltcspvdcr - Litecoin SPV wallet and Decred RPC Wallet on LTC-DCR market
113174
ltcelectrumdcr - Litecoin Electrum wallet and Decred RPC wallet on LTC-DCR market
114175
dcrdash - RPC wallets on DCR-DASH market
115176
dcrdoge - RPC wallets on DCR-DOGE market
116177
dcrdgb - RPC wallets on DCR-DGB market
117178
dcreth - Decred RPC wallet and Ethereum RPC wallet on DCR-ETH market
179+
dcrspveth - Decred SPV wallet and Ethereum wallet on DCR-ETH market
118180
dcrfiro - RPC wallets on DCR-FIRO market
119181
dcrfiroelectrum - Decred RPC wallet and Firo Electrum wallet on DCR-FIRO market
120182
zecbtc - RPC wallets on ZEC-BTC market
121183
dcrusdc - Decred RPC wallet and Ethereum wallet with usdc.eth test token on market DCR-USDC.ETH
122184
polygondcr - Decred RPC wallet and Polygon RPC wallet on POLYGON-DCR market
123185
dcrusdcpolygon - Decred RPC wallet and Polygon wallet with usdc.polygon test token on market DCR-USDC.POLYGON
186+
ethbtc - Ethereum wallet and Bitcoin RPC wallet on ETH-BTC market
187+
ltceth - Litecoin RPC wallet and Ethereum wallet on LTC-ETH market
188+
bchpolygon - Bitcoin Cash RPC wallet and Polygon wallet on BCH-POLYGON market
189+
ltcdash - Litecoin RPC wallet and Dash RPC wallet on LTC-DASH market
190+
dogepolygon - Dogecoin RPC wallet and Polygon wallet on DOGE-POLYGON market
191+
bcheth - Bitcoin Cash RPC wallet and Ethereum wallet on BCH-ETH market
192+
ltcspveth - Litecoin SPV wallet and Ethereum wallet on LTC-ETH market
193+
firobtc - Firo RPC wallet and Bitcoin RPC wallet on FIRO-BTC market
194+
firobtcspv - Firo RPC wallet and Bitcoin SPV wallet on FIRO-BTC market
195+
firodoge - Firo RPC wallet and Dogecoin RPC wallet on FIRO-DOGE market
196+
btcusdceth - Bitcoin RPC wallet and USDC.ETH token on BTC-USDC.ETH market
197+
btcusdteth - Bitcoin RPC wallet and USDT.ETH token on BTC-USDT.ETH market
198+
ltcusdcbase - Litecoin RPC wallet and USDC.BASE token on LTC-USDC.BASE market
199+
dcrusdtpolygon - Decred RPC wallet and USDT.POLYGON token on DCR-USDT.POLYGON market
200+
dcrusdtbase - Decred RPC wallet and USDT.BASE token on DCR-USDT.BASE market
124201
zclbtc - Zclassic RPC wallet and Bitcoin RPC wallet on ZCL-BTC
125202
126203
---------------------

0 commit comments

Comments
 (0)