Skip to content

Commit

Permalink
Merge pull request #5949 from jmacxx/fix_trade_fee_validation
Browse files Browse the repository at this point in the history
Fix trade fee validation bug
  • Loading branch information
ripcurlx authored Jan 11, 2022
2 parents 2c4d289 + 298aca4 commit 310b9a9
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ private boolean checkFeeAmountBTC(String jsonTxt, Coin tradeAmount, boolean isMa
String description = "Expected BTC fee: " + expectedFee + " sats , actual fee paid: " +
feeValueAsCoin + " sats";
if (expectedFeeAsLong == feeValue) {
log.debug("The fee matched what we expected");
log.debug("The fee matched. " + description);
return true;
}

Expand Down Expand Up @@ -269,9 +269,9 @@ private boolean checkFeeAmountBSQ(String jsonTxt, Coin tradeAmount, boolean isMa
minFeeParam);
long feeValue = jsonVIn0Value.getAsLong() - jsonFeeValue.getAsLong();
// if the first output (BSQ) is greater than the first input (BSQ) include the second input (presumably BSQ)
if (jsonFeeValue.getAsLong() > jsonVIn0Value.getAsLong()) {
if ((jsonFeeValue.getAsLong() > jsonVIn0Value.getAsLong() ||
expectedFee.getValue() > jsonVIn0Value.getAsLong()) && jsonVin.size() > 2) {
// in this case 2 or more UTXOs were spent to pay the fee:
//TODO missing handling of > 2 BSQ inputs
JsonObject jsonVin1 = jsonVin.get(1).getAsJsonObject();
JsonElement jsonVIn1Value = jsonVin1.getAsJsonObject("prevout").get("value");
feeValue += jsonVIn1Value.getAsLong();
Expand All @@ -282,7 +282,7 @@ private boolean checkFeeAmountBSQ(String jsonTxt, Coin tradeAmount, boolean isMa
(double) expectedFeeAsLong / 100.0, (double) feeValue / 100.0);

if (expectedFeeAsLong == feeValue) {
log.debug("The fee matched what we expected");
log.debug("The fee matched. " + description);
return true;
}

Expand Down
54 changes: 44 additions & 10 deletions core/src/test/java/bisq/core/provider/mempool/TxValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import bisq.core.dao.governance.param.Param;
import bisq.core.dao.state.DaoStateService;
import bisq.core.filter.Filter;
import bisq.core.filter.FilterManager;
import bisq.core.trade.DelayedPayoutAddressProvider;
import bisq.core.util.FeeReceiverSelector;
Expand Down Expand Up @@ -73,35 +74,37 @@ public TxValidatorTest() {
}

@Test
public void testMakerTx() throws InterruptedException {
public void testMakerTx() {
String mempoolData, offerData;

// paid the correct amount of BSQ fees
offerData = "msimscqb,0636bafb14890edfb95465e66e2b1e15915f7fb595f9b653b9129c15ef4c1c4b,1000000,10,0,662390";
mempoolData = "{\"txid\":\"0636bafb14890edfb95465e66e2b1e15915f7fb595f9b653b9129c15ef4c1c4b\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":7899}},{\"vout\":2,\"prevout\":{\"value\":54877439}}],\"vout\":[{\"scriptpubkey_address\":\"1FCUu7hqKCSsGhVJaLbGEoCWdZRJRNqq8w\",\"value\":7889},{\"scriptpubkey_address\":\"bc1qkj5l4wxl00ufdx6ygcnrck9fz5u927gkwqcgey\",\"value\":1600000},{\"scriptpubkey_address\":\"bc1qkw4a8u9l5w9fhdh3ue9v7e7celk4jyudzg5gk5\",\"value\":53276799}],\"size\":405,\"weight\":1287,\"fee\":650,\"status\":{\"confirmed\":true,\"block_height\":663140}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// paid the correct amount of BSQ fees with two UTXOs
offerData = "qmmtead,94b2589f3270caa0df63437707d4442cae34498ee5b0285090deed9c0ce8584d,800000,10,0,705301";
mempoolData = "{\"txid\":\"94b2589f3270caa0df63437707d4442cae34498ee5b0285090deed9c0ce8584d\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":577}},{\"vout\":0,\"prevout\":{\"value\":19989}},{\"vout\":2,\"prevout\":{\"value\":3008189}}],\"vout\":[{\"scriptpubkey_address\":\"bc1q48p2nvqf3tepjy7x33c5sfx3tp89e8c05z46cs\",\"value\":20555},{\"scriptpubkey_address\":\"bc1q9h69k8l0vy2yv3c72lw2cgn95sd7hlwjjzul05\",\"value\":920000},{\"scriptpubkey_address\":\"bc1qxmwscy2krw7zzfryw5g8868dexfy6pnq9yx3rv\",\"value\":2085750}],\"size\":550,\"weight\":1228,\"fee\":2450,\"status\":{\"confirmed\":true,\"block_height\":705301}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// UNDERPAID expected 1.01 BSQ, actual fee paid 0.80 BSQ (USED 8.00 RATE INSTEAD OF 10.06 RATE)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "48067552,3b6009da764b71d79a4df8e2d8960b6919cae2e9bdccd5ef281e261fa9cd31b3,10000000,80,0,667656";
mempoolData = "{\"txid\":\"3b6009da764b71d79a4df8e2d8960b6919cae2e9bdccd5ef281e261fa9cd31b3\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9717}},{\"vout\":0,\"prevout\":{\"value\":4434912}},{\"vout\":2,\"prevout\":{\"value\":12809932}}],\"vout\":[{\"scriptpubkey_address\":\"1Nzqa4J7ck5bgz7QNXKtcjZExAvReozFo4\",\"value\":9637},{\"scriptpubkey_address\":\"bc1qhmmulf5prreqhccqy2wqpxxn6dcye7ame9dd57\",\"value\":11500000},{\"scriptpubkey_address\":\"bc1qx6hg8km2jdjc5ukhuedmkseu9wlsjtd8zeajpj\",\"value\":5721894}],\"size\":553,\"weight\":1879,\"fee\":23030,\"status\":{\"confirmed\":true,\"block_height\":667660}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// UNDERPAID Expected fee: 0.61 BSQ, actual fee paid: 0.35 BSQ (USED 5.75 RATE INSTEAD OF 10.06 RATE)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "am7DzIv,4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189,6100000,35,0,668195";
mempoolData = "{\"txid\":\"4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":23893}},{\"vout\":1,\"prevout\":{\"value\":1440000}},{\"vout\":2,\"prevout\":{\"value\":16390881}}],\"vout\":[{\"scriptpubkey_address\":\"1Kmrzq3WGCQsZw5kroEphuk1KgsEr65yB7\",\"value\":23858},{\"scriptpubkey_address\":\"bc1qyw5qql9m7rkse9mhcun225nrjpwycszsa5dpjg\",\"value\":7015000},{\"scriptpubkey_address\":\"bc1q90y3p6mg0pe3rvvzfeudq4mfxafgpc9rulruff\",\"value\":10774186}],\"size\":554,\"weight\":1559,\"fee\":41730,\"status\":{\"confirmed\":true,\"block_height\":668198}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// UNDERPAID expected 0.11 BSQ, actual fee paid 0.08 BSQ (USED 5.75 RATE INSTEAD OF 7.53)
// PASS due to leniency rule of accepting old DAO rate parameters: https://github.com/bisq-network/bisq/issues/5329#issuecomment-803223859
offerData = "F1dzaFNQ,f72e263947c9dee6fbe7093fc85be34a149ef5bcfdd49b59b9cc3322fea8967b,1440000,8,0,670822, bsq paid too little";
mempoolData = "{\"txid\":\"f72e263947c9dee6fbe7093fc85be34a149ef5bcfdd49b59b9cc3322fea8967b\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":15163}},{\"vout\":2,\"prevout\":{\"value\":6100000}}],\"vout\":[{\"scriptpubkey_address\":\"1MEsc2m4MSomNJWSr1p6fhnUQMyA3DRGrN\",\"value\":15155},{\"scriptpubkey_address\":\"bc1qztgwe9ry9a9puchjuscqdnv4v9lsm2ut0jtfec\",\"value\":2040000},{\"scriptpubkey_address\":\"bc1q0nstwxc0vqkj4x000xt328mfjapvlsd56nn70h\",\"value\":4048308}],\"size\":406,\"weight\":1291,\"fee\":11700,\"status\":{\"confirmed\":true,\"block_height\":670823}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateMakerFeeTx(mempoolData, btcFeeReceivers).getResult());
}

@Test
public void testTakerTx() throws InterruptedException {
public void testTakerTx() {
String mempoolData, offerData;

// The fee was more than what we expected: Expected BTC fee: 5000 sats , actual fee paid: 6000 sats
Expand Down Expand Up @@ -131,13 +134,25 @@ public void testTakerTx() throws InterruptedException {

// UNDERPAID: Expected fee: 1029000 sats BTC, actual fee paid: 441000 sats BTC because they used the default rate of 0.003 should have been 0.007 per BTC
// after 1.6.0 we introduce additional leniency to allow the default rate (which is not stored in the DAO param change list)
// after 1.8.0 we use fee values obtained from filter => result=false meaning the user did not pay enough
offerData = "AKA,6779b7571f21a5a1af01d675bf032b8a3c571416d05345491018cbc2d016e888,147000000,441000,1,676543";
mempoolData = "{'txid':'6779b7571f21a5a1af01d675bf032b8a3c571416d05345491018cbc2d016e888','version':1,'locktime':0,'vin':[{'txid':'94c36c0a9c5c99844ddfe17ef05a3ebbe94b14d76ee4bed7b00c7d45e681b441','vout':0,'prevout':{'scriptpubkey_address':'bc1qt5uprdzeh9g4el0k9cttn40qzagvpca9q0q6vl','value':177920825},'sequence':4294967295}],'vout':[{'scriptpubkey_address':'19BNi5EpZhgBBWAt5ka7xWpJpX2ZWJEYyq','value':441000},{'scriptpubkey_address':'bc1qxxcl9dz6usrx4z456g6fg8n3u9327hl458d6mx','value':177008388},{'scriptpubkey_address':'bc1qdq0894p2nmg04ceyqgapln6addfl80zy7z36jd','value':467243}],'size':256,'weight':697,'fee':4194,'status':{'confirmed':true,'block_height':676543}}";
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// UNDERPAID: Expected fee: 2.12 BSQ, actual fee paid: 0.03 BSQ
// this is the example from the BSQ fee scammer Oct 2021
offerData = "957500,26e1a5e1f842cb7baa18bd197bd084e7f043d07720b9853e947158eb0a32677d,2000000,101,0,709426";
mempoolData = "{\"txid\":\"26e1a5e1f842cb7baa18bd197bd084e7f043d07720b9853e947158eb0a32677d\",\"version\":1,\"locktime\":0,\"vin\":[{\"txid\":\"\",\"vout\":0,\"prevout\":{\"scriptpubkey\":\"\",\"scriptpubkey_asm\":\"\",\"scriptpubkey_type\":\"v0_p2wpkh\",\"scriptpubkey_address\":\"\",\"value\":3688},\"scriptsig\":\"\",\"scriptsig_asm\":\"\",\"witness\":[\"\",\"\"],\"is_coinbase\":false,\"sequence\":4294967295},{\"txid\":\"\",\"vout\":2,\"prevout\":{\"scriptpubkey\":\"\",\"scriptpubkey_asm\":\"\",\"scriptpubkey_type\":\"v0_p2wpkh\",\"scriptpubkey_address\":\"\",\"value\":796203},\"scriptsig\":\"\",\"scriptsig_asm\":\"\",\"witness\":[\"\",\"\"],\"is_coinbase\":false,\"sequence\":4294967295}],\"vout\":[{\"scriptpubkey\":\"\",\"scriptpubkey_asm\":\"\",\"scriptpubkey_type\":\"v0_p2wpkh\",\"scriptpubkey_address\":\"bc1qydcyfe7kp6968hywcp0uek2xvgem3nlx0x0hfy\",\"value\":3685},{\"scriptpubkey\":\"\",\"scriptpubkey_asm\":\"\",\"scriptpubkey_type\":\"v0_p2wpkh\",\"scriptpubkey_address\":\"bc1qc4amk6sd3c4gzxjgd5sdlaegt0r5juq54vnrll\",\"value\":503346},{\"scriptpubkey\":\"\",\"scriptpubkey_asm\":\"\",\"scriptpubkey_type\":\"v0_p2wpkh\",\"scriptpubkey_address\":\"bc1q66e7m8y5lzfk5smg2a80xeaqzhslgeavg9y70t\",\"value\":291187}],\"size\":403,\"weight\":958,\"fee\":1673,\"status\":{\"confirmed\":true,\"block_height\":709426,\"block_hash\":\"\",\"block_time\":1636751288}}";
Assert.assertFalse(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());

// expected fee of 87.96 BSQ, paid fee=87.96 BSQ, was paid using two BSQ UTXOs, this revealed a bug in validation
offerData = "ZHNYCAE,a91c6f1cb62721a7943678547aa814d6f29125ed63ad076073eb5ae7f16a76e9,83000000,101,0,717000";
mempoolData = "{\"txid\":\"a91c6f1cb62721a7943678547aa814d6f29125ed63ad076073eb5ae7f16a76e9\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":3510}},{\"vout\":0,\"prevout\":{\"value\":6190}},{\"vout\":0,\"prevout\":{\"value\":46000000}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qmqphx028eu4tzdvgccf5re52qtv6pmjanrpq29\",\"value\":904},{\"scriptpubkey_address\":\"bc1qtkvu4zeh0g0pce452335tgnswxd8ayxlktfj2s\",\"value\":30007648},{\"scriptpubkey_address\":\"bc1qdatwgzrrntp2m53tpzmax4dxu6md2c0c9vj8ut\",\"value\":15997324}],\"size\":549,\"weight\":1227,\"fee\":3824,\"status\":{\"confirmed\":true,\"block_height\":716444}}";
Assert.assertTrue(createTxValidator(offerData).parseJsonValidateTakerFeeTx(mempoolData, btcFeeReceivers).getResult());
}

@Test
public void testGoodOffers() throws InterruptedException {
public void testGoodOffers() {
Map<String, String> goodOffers = loadJsonTestData("offerTestData.json");
Map<String, String> mempoolData = loadJsonTestData("txInfo.json");
Assert.assertTrue(goodOffers.size() > 0);
Expand All @@ -147,7 +162,7 @@ public void testGoodOffers() throws InterruptedException {
}

@Test
public void testBadOffers() throws InterruptedException {
public void testBadOffers() {
Map<String, String> badOffers = loadJsonTestData("badOfferTestData.json");
Map<String, String> mempoolData = loadJsonTestData("txInfo.json");
Assert.assertTrue(badOffers.size() > 0);
Expand Down Expand Up @@ -205,7 +220,18 @@ private TxValidator createTxValidator(String offerData) {
when(mockedDaoStateService.getParamValueAsCoin(Mockito.any(Param.class), Mockito.anyInt())).thenAnswer(mockGetFeeRate);
when(mockedDaoStateService.getParamValueAsCoin(Mockito.any(Param.class), Mockito.anyString())).thenAnswer(mockGetParamValueAsCoin);
when(mockedDaoStateService.getParamChangeList(Mockito.any())).thenAnswer(mockGetParamChangeList);

Answer<Long> getMakerFeeBsq = invocation -> 1514L;
Answer<Long> getTakerFeeBsq = invocation -> 10597L;
Answer<Long> getMakerFeeBtc = invocation -> 100000L;
Answer<Long> getTakerFeeBtc = invocation -> 700000L;
Filter mockedFilter = mock(Filter.class);
when(mockedFilter.getMakerFeeBsq()).thenAnswer(getMakerFeeBsq);
when(mockedFilter.getTakerFeeBsq()).thenAnswer(getTakerFeeBsq);
when(mockedFilter.getMakerFeeBtc()).thenAnswer(getMakerFeeBtc);
when(mockedFilter.getTakerFeeBtc()).thenAnswer(getTakerFeeBtc);
FilterManager filterManager = mock(FilterManager.class);
when(filterManager.getFilter()).thenReturn(mockedFilter);
TxValidator txValidator = new TxValidator(mockedDaoStateService, txId, Coin.valueOf(amount), isCurrencyForMakerFeeBtc, filterManager);
return txValidator;
} catch (RuntimeException ignore) {
Expand Down Expand Up @@ -234,6 +260,10 @@ Coin mockedLookupFeeRate(Param param, int blockHeight) {
private LinkedHashMap<Long, String> mockedGetFeeRateMap(Param param) {
LinkedHashMap<Long, String> feeMap = new LinkedHashMap<>();
if (param == Param.DEFAULT_MAKER_FEE_BSQ) {
feeMap.put(706305L, "15.14"); // https://github.com/bisq-network/proposals/issues/345
feeMap.put(697011L, "13.16"); // https://github.com/bisq-network/proposals/issues/339
feeMap.put(682901L, "11.45"); // https://github.com/bisq-network/proposals/issues/333
feeMap.put(677862L, "9.95"); // https://github.com/bisq-network/proposals/issues/325
feeMap.put(674707L, "8.66"); // https://github.com/bisq-network/proposals/issues/318
feeMap.put(670027L, "7.53");
feeMap.put(660667L, "10.06");
Expand All @@ -246,6 +276,10 @@ private LinkedHashMap<Long, String> mockedGetFeeRateMap(Param param) {
feeMap.put(585787L, "8.0");
feeMap.put(581107L, "1.6");
} else if (param == Param.DEFAULT_TAKER_FEE_BSQ) {
feeMap.put(706305L, "105.97"); // https://github.com/bisq-network/proposals/issues/345
feeMap.put(697011L, "92.15"); // https://github.com/bisq-network/proposals/issues/339
feeMap.put(682901L, "80.13"); // https://github.com/bisq-network/proposals/issues/333
feeMap.put(677862L, "69.68"); // https://github.com/bisq-network/proposals/issues/325
feeMap.put(674707L, "60.59"); // https://github.com/bisq-network/proposals/issues/318
feeMap.put(670027L, "52.68");
feeMap.put(660667L, "70.39");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e": "FQ0A7G,ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e,15970000,92,0,640438, underpaid but accepted due to use of different DAO parameter",
"4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189": "am7DzIv,4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189,6100000,35,0,668195, underpaid but accepted due to use of different DAO parameter",
"051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b": "046698,051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b,15970000,92,0,667927, bsq fee underpaid using 5.75 rate for some weird reason",
"37fba8bf119c289481eef031c0a35e126376f71d13d7cce35eb0d5e05799b5da": "hUWPf,37fba8bf119c289481eef031c0a35e126376f71d13d7cce35eb0d5e05799b5da,19910000,200,0,668994, tx_missing_from_blockchain_for_4_days",
"b3bc726aa2aa6533cb1e61901ce351eecde234378fe650aee267388886aa6e4b": "ebdttmzh,b3bc726aa2aa6533cb1e61901ce351eecde234378fe650aee267388886aa6e4b,4000000,5000,1,669137, tx_missing_from_blockchain_for_2_days",
"10f32fe53081466f003185a9ef0324d6cbe3f59334ee9ccb2f7155cbfad9c1de": "kmbyoexc,10f32fe53081466f003185a9ef0324d6cbe3f59334ee9ccb2f7155cbfad9c1de,33000000,332,0,668954, tx_not_found",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189": "am7DzIv,4cdea8872a7d96210f378e0221dc1aae8ee9abb282582afa7546890fb39b7189,6100000,35,0,668195, underpaid but accepted due to use of different DAO parameter",
"ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e": "FQ0A7G,ef1ea38b46402deb7df08c13a6dc379a65542a6940ac9d4ba436641ffd4bcb6e,15970000,92,0,640438, underpaid but accepted due to use of different DAO parameter",
"051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b": "046698,051770f8d7f43a9b6ca10fefa6cdf4cb124a81eed26dc8af2e40f57d2589107b,15970000,92,0,667927, bsq fee underpaid using 5.75 rate for some weird reason",
"e125fdbd09ee86c01e16e1f12a31507cfb8703ed1bd5a221461adf33cb3e00d9": "7213472,e125fdbd09ee86c01e16e1f12a31507cfb8703ed1bd5a221461adf33cb3e00d9,200000000,200000,1,578672, unknown_fee_receiver_1PUXU1MQ",
"44b00de808d0145f9a948fe1b020c5d4173402ba0b5a5ba69124c67e371bca18": "aAPLmh98,44b00de808d0145f9a948fe1b020c5d4173402ba0b5a5ba69124c67e371bca18,140000000,140000,1,578629, unknown_fee_receiver_1PUXU1MQ",
"654a7a34321b57be6a553052d1d9e0f1764dd2fab7b64c9422e9953e4d9d127d": "pwdbdku,654a7a34321b57be6a553052d1d9e0f1764dd2fab7b64c9422e9953e4d9d127d,24980000,238000,1,554947, unknown_fee_receiver_18GzH11",
Expand Down

0 comments on commit 310b9a9

Please sign in to comment.