Merge branch 'cancel-sell-name-fixes'

This commit is contained in:
CalDescent 2023-01-28 12:11:42 +00:00
commit 7fc170575c
6 changed files with 108 additions and 6 deletions

View File

@ -102,6 +102,21 @@ public class NamesDatabaseIntegrityCheck {
}
}
// Process CANCEL_SELL_NAME transactions
if (currentTransaction.getType() == TransactionType.CANCEL_SELL_NAME) {
CancelSellNameTransactionData cancelSellNameTransactionData = (CancelSellNameTransactionData) currentTransaction;
Name nameObj = new Name(repository, cancelSellNameTransactionData.getName());
if (nameObj != null && nameObj.getNameData() != null) {
nameObj.cancelSell(cancelSellNameTransactionData);
modificationCount++;
LOGGER.trace("Processed CANCEL_SELL_NAME transaction for name {}", name);
}
else {
// Something went wrong
throw new DataException(String.format("Name data not found for name %s", cancelSellNameTransactionData.getName()));
}
}
// Process BUY_NAME transactions
if (currentTransaction.getType() == TransactionType.BUY_NAME) {
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) currentTransaction;
@ -128,7 +143,7 @@ public class NamesDatabaseIntegrityCheck {
public int rebuildAllNames() {
int modificationCount = 0;
try (final Repository repository = RepositoryManager.getRepository()) {
List<String> names = this.fetchAllNames(repository);
List<String> names = this.fetchAllNames(repository); // TODO: de-duplicate, to speed up this process
for (String name : names) {
modificationCount += this.rebuildName(name, repository);
}
@ -326,6 +341,10 @@ public class NamesDatabaseIntegrityCheck {
TransactionType.BUY_NAME, Arrays.asList("name = ?"), Arrays.asList(name));
signatures.addAll(buyNameTransactions);
List<byte[]> cancelSellNameTransactions = repository.getTransactionRepository().getSignaturesMatchingCustomCriteria(
TransactionType.CANCEL_SELL_NAME, Arrays.asList("name = ?"), Arrays.asList(name));
signatures.addAll(cancelSellNameTransactions);
List<TransactionData> transactions = new ArrayList<>();
for (byte[] signature : signatures) {
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
@ -390,6 +409,12 @@ public class NamesDatabaseIntegrityCheck {
names.add(sellNameTransactionData.getName());
}
}
if ((transactionData instanceof CancelSellNameTransactionData)) {
CancelSellNameTransactionData cancelSellNameTransactionData = (CancelSellNameTransactionData) transactionData;
if (!names.contains(cancelSellNameTransactionData.getName())) {
names.add(cancelSellNameTransactionData.getName());
}
}
}
return names;
}

View File

@ -3,6 +3,7 @@ package org.qortal.data.transaction;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlTransient;
import org.qortal.transaction.Transaction.TransactionType;
@ -19,6 +20,11 @@ public class CancelSellNameTransactionData extends TransactionData {
@Schema(description = "which name to cancel selling", example = "my-name")
private String name;
// For internal use when orphaning
@XmlTransient
@Schema(hidden = true)
private Long salePrice;
// Constructors
// For JAXB
@ -30,11 +36,17 @@ public class CancelSellNameTransactionData extends TransactionData {
this.creatorPublicKey = this.ownerPublicKey;
}
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name) {
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name, Long salePrice) {
super(TransactionType.CANCEL_SELL_NAME, baseTransactionData);
this.ownerPublicKey = baseTransactionData.creatorPublicKey;
this.name = name;
this.salePrice = salePrice;
}
/** From network/API */
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name) {
this(baseTransactionData, name, null);
}
// Getters / setters
@ -47,4 +59,12 @@ public class CancelSellNameTransactionData extends TransactionData {
return this.name;
}
public Long getSalePrice() {
return this.salePrice;
}
public void setSalePrice(Long salePrice) {
this.salePrice = salePrice;
}
}

View File

@ -180,8 +180,12 @@ public class Name {
}
public void cancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException {
// Mark not for-sale but leave price in case we want to orphan
// Update previous sale price in transaction data
cancelSellNameTransactionData.setSalePrice(this.nameData.getSalePrice());
// Mark not for-sale
this.nameData.setIsForSale(false);
this.nameData.setSalePrice(null);
// Save sale info into repository
this.repository.getNameRepository().save(this.nameData);
@ -190,6 +194,7 @@ public class Name {
public void uncancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException {
// Mark as for-sale using existing price
this.nameData.setIsForSale(true);
this.nameData.setSalePrice(cancelSellNameTransactionData.getSalePrice());
// Save no-sale info into repository
this.repository.getNameRepository().save(this.nameData);

View File

@ -988,6 +988,11 @@ public class HSQLDBDatabaseUpdates {
stmt.execute("CREATE INDEX ChatTransactionsChatReferenceIndex ON ChatTransactions (chat_reference)");
break;
case 46:
// We need to track the sale price when canceling a name sale, so it can be put back when orphaned
stmt.execute("ALTER TABLE CancelSellNameTransactions ADD sale_price QortalAmount");
break;
default:
// nothing to do
return false;

View File

@ -17,15 +17,16 @@ public class HSQLDBCancelSellNameTransactionRepository extends HSQLDBTransaction
}
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
String sql = "SELECT name FROM CancelSellNameTransactions WHERE signature = ?";
String sql = "SELECT name, sale_price FROM CancelSellNameTransactions WHERE signature = ?";
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
if (resultSet == null)
return null;
String name = resultSet.getString(1);
Long salePrice = resultSet.getLong(2);
return new CancelSellNameTransactionData(baseTransactionData, name);
return new CancelSellNameTransactionData(baseTransactionData, name, salePrice);
} catch (SQLException e) {
throw new DataException("Unable to fetch cancel sell name transaction from repository", e);
}
@ -38,7 +39,7 @@ public class HSQLDBCancelSellNameTransactionRepository extends HSQLDBTransaction
HSQLDBSaver saveHelper = new HSQLDBSaver("CancelSellNameTransactions");
saveHelper.bind("signature", cancelSellNameTransactionData.getSignature()).bind("owner", cancelSellNameTransactionData.getOwnerPublicKey()).bind("name",
cancelSellNameTransactionData.getName());
cancelSellNameTransactionData.getName()).bind("sale_price", cancelSellNameTransactionData.getSalePrice());
try {
saveHelper.execute(this.repository);

View File

@ -165,6 +165,52 @@ public class BuySellTests extends Common {
assertEquals("price incorrect", price, nameData.getSalePrice());
}
@Test
public void testCancelSellNameAndRelist() throws DataException {
// Register-name and sell-name
testSellName();
// Cancel Sell-name
CancelSellNameTransactionData transactionData = new CancelSellNameTransactionData(TestTransaction.generateBase(alice), name);
TransactionUtils.signAndMint(repository, transactionData, alice);
NameData nameData;
// Check name is no longer for sale
nameData = repository.getNameRepository().fromName(name);
assertFalse(nameData.isForSale());
assertNull(nameData.getSalePrice());
// Re-sell-name
Long newPrice = random.nextInt(1000) * Amounts.MULTIPLIER;
SellNameTransactionData sellNameTransactionData = new SellNameTransactionData(TestTransaction.generateBase(alice), name, newPrice);
TransactionUtils.signAndMint(repository, sellNameTransactionData, alice);
// Check name is for sale
nameData = repository.getNameRepository().fromName(name);
assertTrue(nameData.isForSale());
assertEquals("price incorrect", newPrice, nameData.getSalePrice());
// Orphan sell-name
BlockUtils.orphanLastBlock(repository);
// Check name no longer for sale
nameData = repository.getNameRepository().fromName(name);
assertFalse(nameData.isForSale());
assertNull(nameData.getSalePrice());
// Orphan cancel-sell-name
BlockUtils.orphanLastBlock(repository);
// Check name is for sale (at original price)
nameData = repository.getNameRepository().fromName(name);
assertTrue(nameData.isForSale());
assertEquals("price incorrect", price, nameData.getSalePrice());
// Orphan sell-name and register-name
BlockUtils.orphanBlocks(repository, 2);
}
@Test
public void testBuyName() throws DataException {
// Register-name and sell-name