qortal/src/qora/transaction/CancelOrderTransaction.java
catbref 7da84b2b85 Arbitrary Transaction support + various fixes
NOTE: requires HSQLDB built from svn rev 5836 or later

Fixed BuyNameTransactionData constructors not picking up nameReference.

Added new "orphan" tool to regress blockchain back to specified block.

Added new Block constructor for when receiving a block from the network.
Fixed Block generatingBalance/forging code to be compliant with v1.
Added logging of transactions that fail validation during block validation.

Fixed buyer/seller balances not being updated during name purchase.

Generally replace BigDecimal.compareTo expressions with "<operator> 0" form.
e.g. instead of someBigDecimal.compareTo(anotherBigDecimal) == 1
we now have someBigDecimal.compareTo(anotherBigDecimal) > 0

Fix amounts involved in BuyNameTransactions.

Renamed Transaction.calcSignature to .sign

Refactored Transaction.toBytesLessSignature to TransactionTransformer.toBytesForSigning,
which itself calls subclass' toBytesForSigningImpl,
which might override Transaction.toBytesForSigningImpl when special v1 mangling is required.

Corrected more cases of NTP.getTime in transaction processing
which should really be transaction's timestmap instead.

Fixed HSQLDB-related issue where strings were padded with spaces during comparison.
Some column types no longer case-insensitive as that mode of comparison
is done during transaction validation.

Added missing option_index column to CreatePollTransactionOptions which was causing
out-of-order options during fetching from repository and hence signature failures.

Added unit tests for v1-special mangled transaction signature checking.

Removed checks for remaining bytes to ByteBuffer in various transaction transformers'
fromByteBuffer() methods as the buffer underflow exception is now caught in
TransactionTransformer.fromBytes.

Corrected byte-related transformations of CreatePollTransactions that were missing
voter counts (albeit always zero).

Corrected byte-related transformations of IssueAssetTransactions that were missing
duplicate signature/reference (v1-special).

Added "txhex" tool to output transaction in hex form, given base58 tx signature.

Added "v1feeder" tool to fetch blocks from v1 node and process them.
2018-08-02 10:02:33 +01:00

141 lines
4.7 KiB
Java

package qora.transaction;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import data.assets.OrderData;
import data.transaction.CancelOrderTransactionData;
import data.transaction.TransactionData;
import qora.account.Account;
import qora.account.PublicKeyAccount;
import qora.assets.Asset;
import qora.assets.Order;
import qora.crypto.Crypto;
import repository.AssetRepository;
import repository.DataException;
import repository.Repository;
public class CancelOrderTransaction extends Transaction {
// Properties
private CancelOrderTransactionData cancelOrderTransactionData;
// Constructors
public CancelOrderTransaction(Repository repository, TransactionData transactionData) {
super(repository, transactionData);
this.cancelOrderTransactionData = (CancelOrderTransactionData) this.transactionData;
}
// More information
public List<Account> getRecipientAccounts() {
return new ArrayList<Account>();
}
public boolean isInvolved(Account account) throws DataException {
return account.getAddress().equals(this.getCreator().getAddress());
}
public BigDecimal getAmount(Account account) throws DataException {
BigDecimal amount = BigDecimal.ZERO.setScale(8);
if (account.getAddress().equals(this.getCreator().getAddress()))
amount = amount.subtract(this.transactionData.getFee());
return amount;
}
// Navigation
public Account getCreator() throws DataException {
return new PublicKeyAccount(this.repository, cancelOrderTransactionData.getCreatorPublicKey());
}
// Processing
@Override
public ValidationResult isValid() throws DataException {
AssetRepository assetRepository = this.repository.getAssetRepository();
// Check fee is positive
if (cancelOrderTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_FEE;
// Check order even exists
OrderData orderData = assetRepository.fromOrderId(cancelOrderTransactionData.getOrderId());
if (orderData == null)
return ValidationResult.ORDER_DOES_NOT_EXIST;
Account creator = getCreator();
// Check creator's public key results in valid address
if (!Crypto.isValidAddress(creator.getAddress()))
return ValidationResult.INVALID_ADDRESS;
// Check creator's public key matches order's creator's public key
Account orderCreator = new PublicKeyAccount(this.repository, orderData.getCreatorPublicKey());
if (!orderCreator.getAddress().equals(creator.getAddress()))
return ValidationResult.INVALID_ORDER_CREATOR;
// Check creator has enough QORA for fee
if (creator.getConfirmedBalance(Asset.QORA).compareTo(cancelOrderTransactionData.getFee()) < 0)
return ValidationResult.NO_BALANCE;
// Check reference is correct
if (!Arrays.equals(creator.getLastReference(), cancelOrderTransactionData.getReference()))
return ValidationResult.INVALID_REFERENCE;
return ValidationResult.OK;
}
@Override
public void process() throws DataException {
Account creator = getCreator();
// Save this transaction itself
this.repository.getTransactionRepository().save(this.transactionData);
// Update creator's balance regarding fee
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(cancelOrderTransactionData.getFee()));
// Update creator's last reference
creator.setLastReference(cancelOrderTransactionData.getSignature());
// Mark Order as completed so no more trades can happen
OrderData orderData = this.repository.getAssetRepository().fromOrderId(cancelOrderTransactionData.getOrderId());
Order order = new Order(this.repository, orderData);
order.cancel();
// Update creator's balance with unfulfilled amount
creator.setConfirmedBalance(orderData.getHaveAssetId(), creator.getConfirmedBalance(orderData.getHaveAssetId()).add(order.getAmountLeft()));
}
@Override
public void orphan() throws DataException {
Account creator = getCreator();
// Save this transaction itself
this.repository.getTransactionRepository().delete(this.transactionData);
// Update creator's balance regarding fee
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(cancelOrderTransactionData.getFee()));
// Update creator's last reference
creator.setLastReference(cancelOrderTransactionData.getReference());
// Unmark Order as completed so trades can happen again
OrderData orderData = this.repository.getAssetRepository().fromOrderId(cancelOrderTransactionData.getOrderId());
Order order = new Order(this.repository, orderData);
order.reopen();
// Update creator's balance with unfulfilled amount
creator.setConfirmedBalance(orderData.getHaveAssetId(), creator.getConfirmedBalance(orderData.getHaveAssetId()).subtract(order.getAmountLeft()));
}
}