forked from Qortal/qortal
Merge branch 'cancel-sell-name-fixes'
This commit is contained in:
commit
7fc170575c
@ -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
|
// Process BUY_NAME transactions
|
||||||
if (currentTransaction.getType() == TransactionType.BUY_NAME) {
|
if (currentTransaction.getType() == TransactionType.BUY_NAME) {
|
||||||
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) currentTransaction;
|
BuyNameTransactionData buyNameTransactionData = (BuyNameTransactionData) currentTransaction;
|
||||||
@ -128,7 +143,7 @@ public class NamesDatabaseIntegrityCheck {
|
|||||||
public int rebuildAllNames() {
|
public int rebuildAllNames() {
|
||||||
int modificationCount = 0;
|
int modificationCount = 0;
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
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) {
|
for (String name : names) {
|
||||||
modificationCount += this.rebuildName(name, repository);
|
modificationCount += this.rebuildName(name, repository);
|
||||||
}
|
}
|
||||||
@ -326,6 +341,10 @@ public class NamesDatabaseIntegrityCheck {
|
|||||||
TransactionType.BUY_NAME, Arrays.asList("name = ?"), Arrays.asList(name));
|
TransactionType.BUY_NAME, Arrays.asList("name = ?"), Arrays.asList(name));
|
||||||
signatures.addAll(buyNameTransactions);
|
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<>();
|
List<TransactionData> transactions = new ArrayList<>();
|
||||||
for (byte[] signature : signatures) {
|
for (byte[] signature : signatures) {
|
||||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
||||||
@ -390,6 +409,12 @@ public class NamesDatabaseIntegrityCheck {
|
|||||||
names.add(sellNameTransactionData.getName());
|
names.add(sellNameTransactionData.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((transactionData instanceof CancelSellNameTransactionData)) {
|
||||||
|
CancelSellNameTransactionData cancelSellNameTransactionData = (CancelSellNameTransactionData) transactionData;
|
||||||
|
if (!names.contains(cancelSellNameTransactionData.getName())) {
|
||||||
|
names.add(cancelSellNameTransactionData.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.qortal.data.transaction;
|
|||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
|
|
||||||
import org.qortal.transaction.Transaction.TransactionType;
|
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")
|
@Schema(description = "which name to cancel selling", example = "my-name")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
// For internal use when orphaning
|
||||||
|
@XmlTransient
|
||||||
|
@Schema(hidden = true)
|
||||||
|
private Long salePrice;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
// For JAXB
|
// For JAXB
|
||||||
@ -30,11 +36,17 @@ public class CancelSellNameTransactionData extends TransactionData {
|
|||||||
this.creatorPublicKey = this.ownerPublicKey;
|
this.creatorPublicKey = this.ownerPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name) {
|
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name, Long salePrice) {
|
||||||
super(TransactionType.CANCEL_SELL_NAME, baseTransactionData);
|
super(TransactionType.CANCEL_SELL_NAME, baseTransactionData);
|
||||||
|
|
||||||
this.ownerPublicKey = baseTransactionData.creatorPublicKey;
|
this.ownerPublicKey = baseTransactionData.creatorPublicKey;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.salePrice = salePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** From network/API */
|
||||||
|
public CancelSellNameTransactionData(BaseTransactionData baseTransactionData, String name) {
|
||||||
|
this(baseTransactionData, name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters / setters
|
// Getters / setters
|
||||||
@ -47,4 +59,12 @@ public class CancelSellNameTransactionData extends TransactionData {
|
|||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getSalePrice() {
|
||||||
|
return this.salePrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalePrice(Long salePrice) {
|
||||||
|
this.salePrice = salePrice;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -180,8 +180,12 @@ public class Name {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void cancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException {
|
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.setIsForSale(false);
|
||||||
|
this.nameData.setSalePrice(null);
|
||||||
|
|
||||||
// Save sale info into repository
|
// Save sale info into repository
|
||||||
this.repository.getNameRepository().save(this.nameData);
|
this.repository.getNameRepository().save(this.nameData);
|
||||||
@ -190,6 +194,7 @@ public class Name {
|
|||||||
public void uncancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException {
|
public void uncancelSell(CancelSellNameTransactionData cancelSellNameTransactionData) throws DataException {
|
||||||
// Mark as for-sale using existing price
|
// Mark as for-sale using existing price
|
||||||
this.nameData.setIsForSale(true);
|
this.nameData.setIsForSale(true);
|
||||||
|
this.nameData.setSalePrice(cancelSellNameTransactionData.getSalePrice());
|
||||||
|
|
||||||
// Save no-sale info into repository
|
// Save no-sale info into repository
|
||||||
this.repository.getNameRepository().save(this.nameData);
|
this.repository.getNameRepository().save(this.nameData);
|
||||||
|
@ -988,6 +988,11 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
stmt.execute("CREATE INDEX ChatTransactionsChatReferenceIndex ON ChatTransactions (chat_reference)");
|
stmt.execute("CREATE INDEX ChatTransactionsChatReferenceIndex ON ChatTransactions (chat_reference)");
|
||||||
break;
|
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:
|
default:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return false;
|
return false;
|
||||||
|
@ -17,15 +17,16 @@ public class HSQLDBCancelSellNameTransactionRepository extends HSQLDBTransaction
|
|||||||
}
|
}
|
||||||
|
|
||||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
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())) {
|
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
String name = resultSet.getString(1);
|
String name = resultSet.getString(1);
|
||||||
|
Long salePrice = resultSet.getLong(2);
|
||||||
|
|
||||||
return new CancelSellNameTransactionData(baseTransactionData, name);
|
return new CancelSellNameTransactionData(baseTransactionData, name, salePrice);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to fetch cancel sell name transaction from repository", 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");
|
HSQLDBSaver saveHelper = new HSQLDBSaver("CancelSellNameTransactions");
|
||||||
|
|
||||||
saveHelper.bind("signature", cancelSellNameTransactionData.getSignature()).bind("owner", cancelSellNameTransactionData.getOwnerPublicKey()).bind("name",
|
saveHelper.bind("signature", cancelSellNameTransactionData.getSignature()).bind("owner", cancelSellNameTransactionData.getOwnerPublicKey()).bind("name",
|
||||||
cancelSellNameTransactionData.getName());
|
cancelSellNameTransactionData.getName()).bind("sale_price", cancelSellNameTransactionData.getSalePrice());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saveHelper.execute(this.repository);
|
saveHelper.execute(this.repository);
|
||||||
|
@ -165,6 +165,52 @@ public class BuySellTests extends Common {
|
|||||||
assertEquals("price incorrect", price, nameData.getSalePrice());
|
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
|
@Test
|
||||||
public void testBuyName() throws DataException {
|
public void testBuyName() throws DataException {
|
||||||
// Register-name and sell-name
|
// Register-name and sell-name
|
||||||
|
Loading…
x
Reference in New Issue
Block a user