|
|
|
@ -29,16 +29,18 @@ import bisq.core.util.coin.BsqFormatter;
|
|
|
|
|
import org.bitcoinj.core.Coin;
|
|
|
|
|
|
|
|
|
|
import com.google.gson.Gson;
|
|
|
|
|
import com.google.gson.reflect.TypeToken;
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.io.IOUtils;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
|
@ -50,6 +52,7 @@ import org.mockito.stubbing.Answer;
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
|
@ -58,7 +61,7 @@ import static org.mockito.Mockito.when;
|
|
|
|
|
public class TxValidatorTest {
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(TxValidatorTest.class);
|
|
|
|
|
|
|
|
|
|
private List<String> btcFeeReceivers = new ArrayList<>();
|
|
|
|
|
private final List<String> btcFeeReceivers = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
public TxValidatorTest() {
|
|
|
|
|
btcFeeReceivers.add("1EKXx73oUhHaUh8JBimtiPGgHfwNmxYKAj");
|
|
|
|
@ -72,12 +75,12 @@ public class TxValidatorTest {
|
|
|
|
|
btcFeeReceivers.add("1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7");
|
|
|
|
|
btcFeeReceivers.add("3A8Zc1XioE2HRzYfbb5P8iemCS72M6vRJV");
|
|
|
|
|
btcFeeReceivers.add(DelayedPayoutAddressProvider.BM3_ADDRESS);
|
|
|
|
|
log.warn("Known BTC fee receivers: {}", btcFeeReceivers.toString());
|
|
|
|
|
log.warn("Known BTC fee receivers: {}", btcFeeReceivers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void testMakerTx() {
|
|
|
|
|
String mempoolData, offerData;
|
|
|
|
|
String /*mempoolData, */offerData;
|
|
|
|
|
|
|
|
|
|
log.info("checking issue from user 2022-10-07");
|
|
|
|
|
offerData = "1322804,5bec4007de1cb8cf18a5fa859d80d66031b8c78cfd99674e09ffd65cf23b50fc,9630000,137,0,757500";
|
|
|
|
@ -121,17 +124,17 @@ public class TxValidatorTest {
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: The fee matched what we expected (BSQ)");
|
|
|
|
|
offerData = "00072328,12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166,6250000,188,0,615955";
|
|
|
|
|
mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":19980}},{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"17qiF1TYgT1YvsCPJyXQoKMtBZ7YJBW9GH\",\"value\":19792},{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":19980}},{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"17qiF1TYgT1YvsCPJyXQoKMtBZ7YJBW9GH\",\"value\":19792},{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
assertTrue(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: No BSQ was burnt (error)");
|
|
|
|
|
offerData = "NOBURN,12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166,6250000,0,0,615955";
|
|
|
|
|
mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":19980}},{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"17qiF1TYgT1YvsCPJyXQoKMtBZ7YJBW9GH\",\"value\":19980},{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":19980}},{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"17qiF1TYgT1YvsCPJyXQoKMtBZ7YJBW9GH\",\"value\":19980},{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
assertFalse(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: No BSQ input (error)");
|
|
|
|
|
offerData = "NOBSQ,12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166,6250000,0,0,615955";
|
|
|
|
|
mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"12f658954890d38ce698355be0b27fdd68d092c7b1b7475381918db060f46166\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":2,\"prevout\":{\"value\":2086015}},{\"vout\":0,\"prevout\":{\"value\":1100000}},{\"vout\":2,\"prevout\":{\"value\":938200}}],\"vout\":[{\"scriptpubkey_address\":\"16aFKD5hvEjJgPme5yRNJT2rAPdTXzdQc2\",\"value\":3768432},{\"scriptpubkey_address\":\"1D5V3QW8f5n4PhwfPgNkW9eWZwNJFyVU8n\",\"value\":346755}],\"size\":701,\"weight\":2804,\"fee\":9216,\"status\":{\"confirmed\":true,\"block_height\":615955}}";
|
|
|
|
|
assertFalse(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: The fee was what we expected: (7000 sats)");
|
|
|
|
@ -141,12 +144,12 @@ public class TxValidatorTest {
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: The fee matched what we expected");
|
|
|
|
|
offerData = "89284,e1269aad63b3d894f5133ad658960971ef5c0fce6a13ad10544dc50fa3360588,900000,47,0,666473";
|
|
|
|
|
mempoolData = "{\"txid\":\"e1269aad63b3d894f5133ad658960971ef5c0fce6a13ad10544dc50fa3360588\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":72738}},{\"vout\":0,\"prevout\":{\"value\":1600000}}],\"vout\":[{\"scriptpubkey_address\":\"17Kh5Ype9yNomqRrqu2k1mdV5c6FcKfGwQ\",\"value\":72691},{\"scriptpubkey_address\":\"bc1qdr9zcw7gf2sehxkux4fmqujm5uguhaqz7l9lca\",\"value\":629016},{\"scriptpubkey_address\":\"bc1qgqrrqv8q6l5d3t52fe28ghuhz4xqrsyxlwn03z\",\"value\":956523}],\"size\":404,\"weight\":1286,\"fee\":14508,\"status\":{\"confirmed\":true,\"block_height\":672388}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"e1269aad63b3d894f5133ad658960971ef5c0fce6a13ad10544dc50fa3360588\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":72738}},{\"vout\":0,\"prevout\":{\"value\":1600000}}],\"vout\":[{\"scriptpubkey_address\":\"17Kh5Ype9yNomqRrqu2k1mdV5c6FcKfGwQ\",\"value\":72691},{\"scriptpubkey_address\":\"bc1qdr9zcw7gf2sehxkux4fmqujm5uguhaqz7l9lca\",\"value\":629016},{\"scriptpubkey_address\":\"bc1qgqrrqv8q6l5d3t52fe28ghuhz4xqrsyxlwn03z\",\"value\":956523}],\"size\":404,\"weight\":1286,\"fee\":14508,\"status\":{\"confirmed\":true,\"block_height\":672388}}";
|
|
|
|
|
assertTrue(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case for UNDERPAID: Expected fee: 7.04 BSQ, actual fee paid: 1.01 BSQ");
|
|
|
|
|
offerData = "VOxRS,e99ea06aefc824fd45031447f7a0b56efb8117a09f9b8982e2c4da480a3a0e91,10000000,101,0,669129";
|
|
|
|
|
mempoolData = "{\"txid\":\"e99ea06aefc824fd45031447f7a0b56efb8117a09f9b8982e2c4da480a3a0e91\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":16739}},{\"vout\":2,\"prevout\":{\"value\":113293809}}],\"vout\":[{\"scriptpubkey_address\":\"1F14nF6zoUfJkqZrFgdmK5VX5QVwEpAnKW\",\"value\":16638},{\"scriptpubkey_address\":\"bc1q80y688ev7u43vqy964yf7feqddvt2mkm8977cm\",\"value\":11500000},{\"scriptpubkey_address\":\"bc1q9whgyc2du9mrgnxz0nl0shwpw8ugrcae0j0w8p\",\"value\":101784485}],\"size\":406,\"weight\":1291,\"fee\":9425,\"status\":{\"confirmed\":true,\"block_height\":669134}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"e99ea06aefc824fd45031447f7a0b56efb8117a09f9b8982e2c4da480a3a0e91\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":16739}},{\"vout\":2,\"prevout\":{\"value\":113293809}}],\"vout\":[{\"scriptpubkey_address\":\"1F14nF6zoUfJkqZrFgdmK5VX5QVwEpAnKW\",\"value\":16638},{\"scriptpubkey_address\":\"bc1q80y688ev7u43vqy964yf7feqddvt2mkm8977cm\",\"value\":11500000},{\"scriptpubkey_address\":\"bc1q9whgyc2du9mrgnxz0nl0shwpw8ugrcae0j0w8p\",\"value\":101784485}],\"size\":406,\"weight\":1291,\"fee\":9425,\"status\":{\"confirmed\":true,\"block_height\":669134}}";
|
|
|
|
|
assertFalse(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case for 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");
|
|
|
|
@ -158,27 +161,27 @@ public class TxValidatorTest {
|
|
|
|
|
|
|
|
|
|
log.info("========== test case for 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,3,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}}";
|
|
|
|
|
//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}}";
|
|
|
|
|
assertFalse(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: expected fee paid using two BSQ UTXOs");
|
|
|
|
|
offerData = "ZHNYCAE,a91c6f1cb62721a7943678547aa814d6f29125ed63ad076073eb5ae7f16a76e9,83000000,8796,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}}";
|
|
|
|
|
//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}}";
|
|
|
|
|
assertTrue(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: expected fee paid using three BSQ UTXOs");
|
|
|
|
|
offerData = "3UTXOGOOD,c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262,200000000,17888,0,733715";
|
|
|
|
|
mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9833}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":17488}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9833}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":17488}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
assertTrue(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: expected fee paid using four BSQ UTXOs");
|
|
|
|
|
offerData = "4UTXOGOOD,c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262,200000000,17888,0,733715";
|
|
|
|
|
mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":4833}},{\"vout\":0,\"prevout\":{\"value\":5000}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":17488}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":4833}},{\"vout\":0,\"prevout\":{\"value\":5000}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":17488}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
assertTrue(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
|
|
|
|
|
log.info("========== test case: three BSQ UTXOs, but fee paid is too low");
|
|
|
|
|
offerData = "3UTXOLOWFEE,c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262,200000000,101,0,733715";
|
|
|
|
|
mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9833}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":1362}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
//mempoolData = "{\"txid\":\"c7dddc267a366fa1d87840eeb0dcd89918a886ccb9aabee80f667635a5d4e262\",\"version\":1,\"locktime\":0,\"vin\":[{\"vout\":0,\"prevout\":{\"value\":9833}},{\"vout\":0,\"prevout\":{\"value\":1362}},{vout\":0,\"prevout\":{\"value\":1362}},{\"vout\":2,\"prevout\":{\"value\":573360131}}],\"vout\":[{\"scriptpubkey_address\":\"bc1qvwpm87kmrlgave9srxk6nfwleehll0kxetu5j0\",\"value\":10795},{\"scriptpubkey_address\":\"bc1qz5n83ppfpdznnzff4e7tjep5c6f6jce9mqnrzh\",\"value\":230004780},{\"scriptpubkey_address\":\"bc1qcfyjajhuv55fyu6g5ug664r57u9a7qg55cgt5p\",\"value\":343370849}],\"size\":699,\"weight\":1500,\"fee\":2390,\"status\":{\"confirmed\":true,\"block_height\":733715}}";
|
|
|
|
|
assertFalse(createTxValidator(offerData).validateBsqFeeTx(false).getResult());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -214,11 +217,11 @@ public class TxValidatorTest {
|
|
|
|
|
assertFalse(expectedResult); // tx was not found in explorer
|
|
|
|
|
} else {
|
|
|
|
|
txValidator.parseJsonValidateMakerFeeTx(jsonTxt, btcFeeReceivers);
|
|
|
|
|
assertTrue(expectedResult == txValidator.getResult());
|
|
|
|
|
assertEquals(expectedResult, txValidator.getResult());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
txValidator.validateBsqFeeTx(true);
|
|
|
|
|
assertTrue(expectedResult == txValidator.getResult());
|
|
|
|
|
assertEquals(expectedResult, txValidator.getResult());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -226,79 +229,64 @@ public class TxValidatorTest {
|
|
|
|
|
private Map<String, String> loadJsonTestData(String fileName) {
|
|
|
|
|
String json = "";
|
|
|
|
|
try {
|
|
|
|
|
json = IOUtils.toString(this.getClass().getResourceAsStream(fileName), "UTF-8");
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
json = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream(fileName)), StandardCharsets.UTF_8);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error(e.toString());
|
|
|
|
|
}
|
|
|
|
|
Map<String, String> map = new Gson().fromJson(json, Map.class);
|
|
|
|
|
return map;
|
|
|
|
|
return new Gson().fromJson(json, new TypeToken<Map<String, String>>() {
|
|
|
|
|
}.getType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// initialize the TxValidator with offerData to be validated
|
|
|
|
|
// and mock the used DaoStateService
|
|
|
|
|
private TxValidator createTxValidator(String offerData) {
|
|
|
|
|
try {
|
|
|
|
|
String[] y = offerData.split(",");
|
|
|
|
|
String txId = y[1];
|
|
|
|
|
long amount = Long.parseLong(y[2]);
|
|
|
|
|
long feePaid = Long.parseLong(y[3]);
|
|
|
|
|
boolean isCurrencyForMakerFeeBtc = Long.parseLong(y[4]) > 0;
|
|
|
|
|
long feePaymentBlockHeight = Long.parseLong(y[5]);
|
|
|
|
|
DaoStateService mockedDaoStateService = mock(DaoStateService.class);
|
|
|
|
|
Tx mockedTx = mock(Tx.class);
|
|
|
|
|
String[] y = offerData.split(",");
|
|
|
|
|
String txId = y[1];
|
|
|
|
|
long amount = Long.parseLong(y[2]);
|
|
|
|
|
long feePaid = Long.parseLong(y[3]);
|
|
|
|
|
boolean isCurrencyForMakerFeeBtc = Long.parseLong(y[4]) > 0;
|
|
|
|
|
long feePaymentBlockHeight = Long.parseLong(y[5]);
|
|
|
|
|
DaoStateService mockedDaoStateService = mock(DaoStateService.class);
|
|
|
|
|
Tx mockedTx = mock(Tx.class);
|
|
|
|
|
|
|
|
|
|
Answer<Coin> mockGetFeeRate = invocation -> {
|
|
|
|
|
return mockedLookupFeeRate(invocation.getArgument(0), invocation.getArgument(1));
|
|
|
|
|
};
|
|
|
|
|
Answer<Coin> mockGetParamValueAsCoin = invocation -> {
|
|
|
|
|
return mockedGetParamValueAsCoin(invocation.getArgument(0), invocation.getArgument(1));
|
|
|
|
|
};
|
|
|
|
|
Answer<List<Coin>> mockGetParamChangeList = invocation -> {
|
|
|
|
|
return mockedGetParamChangeList(invocation.getArgument(0));
|
|
|
|
|
};
|
|
|
|
|
Answer<Optional<Tx>> mockGetBsqTx = invocation -> {
|
|
|
|
|
return Optional.of(mockedTx);
|
|
|
|
|
};
|
|
|
|
|
Answer<Long> mockGetBurntBsq = invocation -> {
|
|
|
|
|
return feePaid;
|
|
|
|
|
};
|
|
|
|
|
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);
|
|
|
|
|
when(mockedDaoStateService.getTx(Mockito.any())).thenAnswer(mockGetBsqTx);
|
|
|
|
|
when(mockedTx.getBurntBsq()).thenAnswer(mockGetBurntBsq);
|
|
|
|
|
Answer<Coin> mockGetFeeRate = invocation ->
|
|
|
|
|
mockedLookupFeeRate(invocation.getArgument(0), invocation.getArgument(1));
|
|
|
|
|
Answer<Coin> mockGetParamValueAsCoin = invocation ->
|
|
|
|
|
mockedGetParamValueAsCoin(invocation.getArgument(0), invocation.getArgument(1));
|
|
|
|
|
Answer<List<Coin>> mockGetParamChangeList = invocation ->
|
|
|
|
|
mockedGetParamChangeList(invocation.getArgument(0));
|
|
|
|
|
Answer<Optional<Tx>> mockGetBsqTx = invocation ->
|
|
|
|
|
Optional.of(mockedTx);
|
|
|
|
|
Answer<Long> mockGetBurntBsq = invocation ->
|
|
|
|
|
feePaid;
|
|
|
|
|
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);
|
|
|
|
|
when(mockedDaoStateService.getTx(Mockito.any())).thenAnswer(mockGetBsqTx);
|
|
|
|
|
when(mockedTx.getBurntBsq()).thenAnswer(mockGetBurntBsq);
|
|
|
|
|
|
|
|
|
|
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, feePaymentBlockHeight, filterManager);
|
|
|
|
|
return txValidator;
|
|
|
|
|
} catch (RuntimeException ignore) {
|
|
|
|
|
// If input format is not as expected we ignore entry
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
Filter mockedFilter = mock(Filter.class);
|
|
|
|
|
when(mockedFilter.getMakerFeeBsq()).thenReturn(1514L);
|
|
|
|
|
when(mockedFilter.getTakerFeeBsq()).thenReturn(10597L);
|
|
|
|
|
when(mockedFilter.getMakerFeeBtc()).thenReturn(100000L);
|
|
|
|
|
when(mockedFilter.getTakerFeeBtc()).thenReturn(700000L);
|
|
|
|
|
FilterManager filterManager = mock(FilterManager.class);
|
|
|
|
|
when(filterManager.getFilter()).thenReturn(mockedFilter);
|
|
|
|
|
return new TxValidator(mockedDaoStateService, txId, Coin.valueOf(amount), isCurrencyForMakerFeeBtc, feePaymentBlockHeight, filterManager);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Coin mockedLookupFeeRate(Param param, int blockHeight) {
|
|
|
|
|
private Coin mockedLookupFeeRate(Param param, int blockHeight) {
|
|
|
|
|
BsqFormatter bsqFormatter = new BsqFormatter();
|
|
|
|
|
LinkedHashMap<Long, String> feeMap = mockedGetFeeRateMap(param);
|
|
|
|
|
for (Map.Entry<Long, String> entry : feeMap.entrySet()) {
|
|
|
|
|
if (blockHeight >= entry.getKey()) {
|
|
|
|
|
if (param.equals(Param.DEFAULT_MAKER_FEE_BTC) || param.equals(Param.DEFAULT_TAKER_FEE_BTC))
|
|
|
|
|
if (param == Param.DEFAULT_MAKER_FEE_BTC || param == Param.DEFAULT_TAKER_FEE_BTC)
|
|
|
|
|
return bsqFormatter.parseToBTC(entry.getValue());
|
|
|
|
|
else
|
|
|
|
|
return ParsingUtils.parseToCoin(entry.getValue(), bsqFormatter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (param.equals(Param.DEFAULT_MAKER_FEE_BTC) || param.equals(Param.DEFAULT_TAKER_FEE_BTC))
|
|
|
|
|
if (param == Param.DEFAULT_MAKER_FEE_BTC || param == Param.DEFAULT_TAKER_FEE_BTC)
|
|
|
|
|
return bsqFormatter.parseToBTC(param.getDefaultValue());
|
|
|
|
|
else
|
|
|
|
|
return ParsingUtils.parseToCoin(param.getDefaultValue(), bsqFormatter);
|
|
|
|
@ -354,14 +342,14 @@ public class TxValidatorTest {
|
|
|
|
|
return feeMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Coin mockedGetParamValueAsCoin(Param param, String paramValue) {
|
|
|
|
|
private Coin mockedGetParamValueAsCoin(Param param, String paramValue) {
|
|
|
|
|
BsqFormatter bsqFormatter = new BsqFormatter();
|
|
|
|
|
return bsqFormatter.parseParamValueToCoin(param, paramValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<Coin> mockedGetParamChangeList(Param param) {
|
|
|
|
|
private List<Coin> mockedGetParamChangeList(Param param) {
|
|
|
|
|
BsqFormatter bsqFormatter = new BsqFormatter();
|
|
|
|
|
List<Coin> retVal = new ArrayList<Coin>();
|
|
|
|
|
List<Coin> retVal = new ArrayList<>();
|
|
|
|
|
Map<Long, String> feeMap = mockedGetFeeRateMap(param);
|
|
|
|
|
for (Map.Entry<Long, String> entry : feeMap.entrySet()) {
|
|
|
|
|
retVal.add(ParsingUtils.parseToCoin(entry.getValue(), bsqFormatter));
|
|
|
|
|