3
0
mirror of https://github.com/Qortal/qortal.git synced 2025-02-11 17:55:50 +00:00

More migration of Assets/Orders and TransferAssetTransactions

This commit is contained in:
catbref 2018-06-14 13:09:55 +01:00
parent 2c23acfa74
commit 2f8c160627
13 changed files with 573 additions and 108 deletions

View File

@ -0,0 +1,74 @@
package data.assets;
import java.math.BigDecimal;
public class OrderData implements Comparable<OrderData> {
private byte[] orderId;
private byte[] creatorPublicKey;
private long haveAssetId;
private long wantAssetId;
private BigDecimal amount;
private BigDecimal fulfilled;
private BigDecimal price;
private long timestamp;
public OrderData(byte[] orderId, byte[] creatorPublicKey, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal fulfilled, BigDecimal price,
long timestamp) {
this.orderId = orderId;
this.creatorPublicKey = creatorPublicKey;
this.haveAssetId = haveAssetId;
this.wantAssetId = wantAssetId;
this.amount = amount;
this.fulfilled = fulfilled;
this.price = price;
this.timestamp = timestamp;
}
public OrderData(byte[] orderId, byte[] creatorPublicKey, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal price, long timestamp) {
this(orderId, creatorPublicKey, haveAssetId, wantAssetId, amount, BigDecimal.ZERO.setScale(8), price, timestamp);
}
public byte[] getOrderId() {
return this.orderId;
}
public byte[] getCreatorPublicKey() {
return this.creatorPublicKey;
}
public long getHaveAssetId() {
return this.haveAssetId;
}
public long getWantAssetId() {
return this.wantAssetId;
}
public BigDecimal getAmount() {
return this.amount;
}
public BigDecimal getFulfilled() {
return this.fulfilled;
}
public void setFulfilled(BigDecimal fulfilled) {
this.fulfilled = fulfilled;
}
public BigDecimal getPrice() {
return this.price;
}
public long getTimestamp() {
return this.timestamp;
}
@Override
public int compareTo(OrderData orderData) {
// Compare using prices
return this.price.compareTo(orderData.getPrice());
}
}

View File

@ -0,0 +1,50 @@
package data.transaction;
import java.math.BigDecimal;
import qora.transaction.Transaction.TransactionType;
public class TransferAssetTransactionData extends TransactionData {
// Properties
private byte[] senderPublicKey;
private String recipient;
private BigDecimal amount;
private long assetId;
// Constructors
public TransferAssetTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, long assetId, BigDecimal fee, long timestamp,
byte[] reference, byte[] signature) {
super(TransactionType.TRANSFER_ASSET, fee, senderPublicKey, timestamp, reference, signature);
this.senderPublicKey = senderPublicKey;
this.recipient = recipient;
this.amount = amount;
this.assetId = assetId;
}
public TransferAssetTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, long assetId, BigDecimal fee, long timestamp,
byte[] reference) {
this(senderPublicKey, recipient, amount, assetId, fee, timestamp, reference, null);
}
// Getters/setters
public byte[] getSenderPublicKey() {
return this.senderPublicKey;
}
public String getRecipient() {
return this.recipient;
}
public BigDecimal getAmount() {
return this.amount;
}
public long getAssetId() {
return this.assetId;
}
}

View File

@ -1,5 +1,8 @@
package qora.assets;
import data.assets.AssetData;
import repository.Repository;
public class Asset {
/**
@ -7,4 +10,15 @@ public class Asset {
*/
public static final long QORA = 0L;
// Properties
private Repository repository;
private AssetData assetData;
// Constructors
public Asset(Repository repository, AssetData assetData) {
this.repository = repository;
this.assetData = assetData;
}
}

View File

@ -1,93 +1,39 @@
package qora.assets;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import qora.account.Account;
import transform.TransformationException;
import data.assets.OrderData;
import repository.DataException;
import repository.Repository;
public class Order implements Comparable<Order> {
public class Order {
// Properties
private BigInteger id;
private Account creator;
private long haveAssetId;
private long wantAssetId;
private BigDecimal amount;
private BigDecimal price;
private long timestamp;
// Other properties
private BigDecimal fulfilled;
private Repository repository;
private OrderData orderData;
// Constructors
public Order(BigInteger id, Account creator, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal price, long timestamp) {
this.id = id;
this.creator = creator;
this.haveAssetId = haveAssetId;
this.wantAssetId = wantAssetId;
this.amount = amount;
this.price = price;
this.timestamp = timestamp;
this.fulfilled = BigDecimal.ZERO.setScale(8);
public Order(Repository repository, OrderData orderData) {
this.repository = repository;
this.orderData = orderData;
}
public Order(BigInteger id, Account creator, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal fulfilled, BigDecimal price,
long timestamp) {
this(id, creator, haveAssetId, wantAssetId, amount, price, timestamp);
// Getters/Setters
this.fulfilled = fulfilled;
}
// Getters/setters
public BigInteger getId() {
return this.id;
}
public Account getCreator() {
return this.creator;
}
public long getHaveAssetId() {
return this.haveAssetId;
}
public long getWantAssetId() {
return this.wantAssetId;
}
public BigDecimal getAmount() {
return this.amount;
}
public BigDecimal getPrice() {
return this.price;
}
public long getTimestamp() {
return this.timestamp;
}
public BigDecimal getFulfilled() {
return this.fulfilled;
}
public void setFulfilled(BigDecimal fulfilled) {
this.fulfilled = fulfilled;
public OrderData getOrderData() {
return this.orderData;
}
// More information
public BigDecimal getAmountLeft() {
return this.amount.subtract(this.fulfilled);
return this.orderData.getAmount().subtract(this.orderData.getFulfilled());
}
public boolean isFulfilled() {
return this.fulfilled.compareTo(this.amount) == 0;
return this.orderData.getFulfilled().compareTo(this.orderData.getAmount()) == 0;
}
// TODO
@ -96,8 +42,6 @@ public class Order implements Comparable<Order> {
// TODO
// public boolean isConfirmed() {}
// Load/Save/Delete
// Navigation
// XXX is this getInitiatedTrades() above?
@ -107,35 +51,14 @@ public class Order implements Comparable<Order> {
return null;
}
// Converters
public static Order parse(byte[] data) throws TransformationException {
// TODO
return null;
}
public byte[] toBytes() {
// TODO
return null;
}
// Processing
// Other
@Override
public int compareTo(Order order) {
// Compare using prices
return this.price.compareTo(order.getPrice());
public void process() throws DataException {
// TODO
}
public Order copy() {
try {
return parse(this.toBytes());
} catch (TransformationException e) {
return null;
}
public void orphan() throws DataException {
// TODO
}
}

View File

@ -1,8 +1,18 @@
package qora.transaction;
import data.transaction.TransactionData;
import java.math.BigDecimal;
import java.util.Arrays;
import data.assets.AssetData;
import data.assets.OrderData;
import data.transaction.CreateOrderTransactionData;
import data.transaction.TransactionData;
import qora.account.Account;
import qora.account.PublicKeyAccount;
import qora.assets.Asset;
import qora.assets.Order;
import qora.block.Block;
import repository.AssetRepository;
import repository.DataException;
import repository.Repository;
@ -27,17 +37,117 @@ public class CreateOrderTransaction extends Transaction {
// Processing
public ValidationResult isValid() throws DataException {
// TODO
CreateOrderTransactionData createOrderTransactionData = (CreateOrderTransactionData) this.transactionData;
long haveAssetId = createOrderTransactionData.getHaveAssetId();
long wantAssetId = createOrderTransactionData.getWantAssetId();
// Check have/want assets are not the same
if (haveAssetId == wantAssetId)
return ValidationResult.HAVE_EQUALS_WANT;
// Check amount is positive
if (createOrderTransactionData.getAmount().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_AMOUNT;
// Check price is positive
if (createOrderTransactionData.getPrice().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_PRICE;
// Check fee is positive
if (createOrderTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_FEE;
AssetRepository assetRepository = this.repository.getAssetRepository();
// Check "have" asset exists
AssetData haveAssetData = assetRepository.fromAssetId(haveAssetId);
if (haveAssetData == null)
return ValidationResult.ASSET_DOES_NOT_EXIST;
// Check "want" asset exists
AssetData wantAssetData = assetRepository.fromAssetId(wantAssetId);
if (wantAssetData == null)
return ValidationResult.ASSET_DOES_NOT_EXIST;
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
// Check reference is correct
if (!Arrays.equals(creator.getLastReference(), createOrderTransactionData.getReference()))
return ValidationResult.INVALID_REFERENCE;
// Check order creator has enough asset balance AFTER removing fee, in case asset is QORA
// If asset is QORA then we need to check amount + fee in one go
if (haveAssetId == Asset.QORA) {
// Check creator has enough funds for amount + fee in QORA
if (creator.getConfirmedBalance(Asset.QORA).compareTo(createOrderTransactionData.getAmount().add(createOrderTransactionData.getFee())) == -1)
return ValidationResult.NO_BALANCE;
} else {
// Check creator has enough funds for amount in whatever asset
if (creator.getConfirmedBalance(haveAssetId).compareTo(createOrderTransactionData.getAmount()) == -1)
return ValidationResult.NO_BALANCE;
// Check creator has enough funds for fee in QORA
// NOTE: in Gen1 pre-POWFIX-RELEASE transactions didn't have this check
if (createOrderTransactionData.getTimestamp() >= Block.POWFIX_RELEASE_TIMESTAMP
&& creator.getConfirmedBalance(Asset.QORA).compareTo(createOrderTransactionData.getFee()) == -1)
return ValidationResult.NO_BALANCE;
}
// Check "have" amount is integer if "have" asset is not divisible
if (!haveAssetData.getIsDivisible() && createOrderTransactionData.getAmount().stripTrailingZeros().scale() > 0)
return ValidationResult.INVALID_AMOUNT;
// Check total return from fulfilled order would be integer if "want" asset is not divisible
if (!wantAssetData.getIsDivisible()
&& createOrderTransactionData.getAmount().multiply(createOrderTransactionData.getPrice()).stripTrailingZeros().scale() > 0)
return ValidationResult.INVALID_RETURN;
return ValidationResult.OK;
}
public void process() throws DataException {
// TODO
CreateOrderTransactionData createOrderTransactionData = (CreateOrderTransactionData) this.transactionData;
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
// Update creator's balance due to fee
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createOrderTransactionData.getFee()));
// Update creator's last reference
creator.setLastReference(createOrderTransactionData.getSignature());
// Save this transaction itself
this.repository.getTransactionRepository().save(createOrderTransactionData);
// Order Id is transaction's signature
byte[] orderId = createOrderTransactionData.getSignature();
// Process the order itself
OrderData orderData = new OrderData(orderId, createOrderTransactionData.getCreatorPublicKey(), createOrderTransactionData.getHaveAssetId(),
createOrderTransactionData.getWantAssetId(), createOrderTransactionData.getAmount(), createOrderTransactionData.getPrice(),
createOrderTransactionData.getTimestamp());
new Order(this.repository, orderData).process();
}
public void orphan() throws DataException {
// TODO
CreateOrderTransactionData createOrderTransactionData = (CreateOrderTransactionData) this.transactionData;
Account creator = new PublicKeyAccount(this.repository, createOrderTransactionData.getCreatorPublicKey());
// Update creator's balance due to fee
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createOrderTransactionData.getFee()));
// Update creator's last reference
creator.setLastReference(createOrderTransactionData.getReference());
// Order Id is transaction's signature
byte[] orderId = createOrderTransactionData.getSignature();
// Orphan the order itself
OrderData orderData = this.repository.getAssetRepository().fromOrderId(orderId);
new Order(this.repository, orderData).orphan();
// Delete this transaction
this.repository.getTransactionRepository().delete(createOrderTransactionData);
}
}

View File

@ -41,8 +41,8 @@ public abstract class Transaction {
// Validation results
public enum ValidationResult {
OK(1), INVALID_ADDRESS(2), NEGATIVE_AMOUNT(3), NEGATIVE_FEE(4), NO_BALANCE(5), INVALID_REFERENCE(6), INVALID_NAME_LENGTH(7), INVALID_DESCRIPTION_LENGTH(
18), INVALID_DATA_LENGTH(27), INVALID_QUANTITY(28), ASSET_DOES_NOT_EXIST(29), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
OK(1), INVALID_ADDRESS(2), NEGATIVE_AMOUNT(3), NEGATIVE_FEE(4), NO_BALANCE(5), INVALID_REFERENCE(6), INVALID_NAME_LENGTH(7), INVALID_AMOUNT(15), INVALID_DESCRIPTION_LENGTH(
18), INVALID_DATA_LENGTH(27), INVALID_QUANTITY(28), ASSET_DOES_NOT_EXIST(29), INVALID_RETURN(30), HAVE_EQUALS_WANT(31), NEGATIVE_PRICE(35), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
public final int value;

View File

@ -0,0 +1,142 @@
package qora.transaction;
import java.math.BigDecimal;
import java.util.Arrays;
import data.assets.AssetData;
import data.transaction.TransactionData;
import data.transaction.TransferAssetTransactionData;
import utils.NTP;
import qora.account.Account;
import qora.account.PublicKeyAccount;
import qora.assets.Asset;
import qora.block.Block;
import qora.crypto.Crypto;
import repository.AssetRepository;
import repository.DataException;
import repository.Repository;
public class TransferAssetTransaction extends Transaction {
// Constructors
public TransferAssetTransaction(Repository repository, TransactionData transactionData) {
super(repository, transactionData);
}
// Processing
@Override
public ValidationResult isValid() throws DataException {
// Lowest cost checks first
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) this.transactionData;
// Are IssueAssetTransactions even allowed at this point?
if (NTP.getTime() < Block.ASSETS_RELEASE_TIMESTAMP)
return ValidationResult.NOT_YET_RELEASED;
// Check recipient address is valid
if (!Crypto.isValidAddress(transferAssetTransactionData.getRecipient()))
return ValidationResult.INVALID_ADDRESS;
// Check amount is positive
if (transferAssetTransactionData.getAmount().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_FEE;
// Check fee is positive
if (transferAssetTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
return ValidationResult.NEGATIVE_FEE;
// Check reference is correct
PublicKeyAccount sender = new PublicKeyAccount(this.repository, transferAssetTransactionData.getSenderPublicKey());
if (!Arrays.equals(sender.getLastReference(), transferAssetTransactionData.getReference()))
return ValidationResult.INVALID_REFERENCE;
// Check sender has enough asset balance AFTER removing fee, in case asset is QORA
long assetId = transferAssetTransactionData.getAssetId();
// If asset is QORA then we need to check amount + fee in one go
if (assetId == Asset.QORA) {
// Check sender has enough funds for amount + fee in QORA
if (sender.getConfirmedBalance(Asset.QORA).compareTo(transferAssetTransactionData.getAmount().add(transferAssetTransactionData.getFee())) == -1)
return ValidationResult.NO_BALANCE;
} else {
// Check sender has enough funds for amount in whatever asset
if (sender.getConfirmedBalance(assetId).compareTo(transferAssetTransactionData.getAmount()) == -1)
return ValidationResult.NO_BALANCE;
// Check sender has enough funds for fee in QORA
// NOTE: in Gen1 pre-POWFIX-RELEASE transactions didn't have this check
if (transferAssetTransactionData.getTimestamp() >= Block.POWFIX_RELEASE_TIMESTAMP
&& sender.getConfirmedBalance(Asset.QORA).compareTo(transferAssetTransactionData.getFee()) == -1)
return ValidationResult.NO_BALANCE;
}
// Check asset amount is integer if asset is not divisible
AssetRepository assetRepository = this.repository.getAssetRepository();
AssetData assetData = assetRepository.fromAssetId(assetId);
if (!assetData.getIsDivisible() && transferAssetTransactionData.getAmount().stripTrailingZeros().scale() > 0)
return ValidationResult.INVALID_AMOUNT;
return ValidationResult.OK;
}
// PROCESS/ORPHAN
@Override
public void process() throws DataException {
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) this.transactionData;
long assetId = transferAssetTransactionData.getAssetId();
// Save this transaction itself
this.repository.getTransactionRepository().save(this.transactionData);
// Update sender's balance due to amount
Account sender = new PublicKeyAccount(this.repository, transferAssetTransactionData.getSenderPublicKey());
sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(transferAssetTransactionData.getAmount()));
// Update sender's balance due to fee
sender.setConfirmedBalance(Asset.QORA, sender.getConfirmedBalance(Asset.QORA).subtract(transferAssetTransactionData.getFee()));
// Update recipient's balance
Account recipient = new Account(this.repository, transferAssetTransactionData.getRecipient());
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(transferAssetTransactionData.getAmount()));
// Update sender's reference
sender.setLastReference(transferAssetTransactionData.getSignature());
// For QORA amounts only: if recipient has no reference yet, then this is their starting reference
if (assetId == Asset.QORA && recipient.getLastReference() == null)
recipient.setLastReference(transferAssetTransactionData.getSignature());
}
@Override
public void orphan() throws DataException {
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) this.transactionData;
long assetId = transferAssetTransactionData.getAssetId();
// Delete this transaction itself
this.repository.getTransactionRepository().delete(this.transactionData);
// Update sender's balance due to amount
Account sender = new PublicKeyAccount(this.repository, transferAssetTransactionData.getSenderPublicKey());
sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).add(transferAssetTransactionData.getAmount()));
// Update sender's balance due to fee
sender.setConfirmedBalance(Asset.QORA, sender.getConfirmedBalance(Asset.QORA).add(transferAssetTransactionData.getFee()));
// Update recipient's balance
Account recipient = new Account(this.repository, transferAssetTransactionData.getRecipient());
recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(transferAssetTransactionData.getAmount()));
// Update sender's reference
sender.setLastReference(transferAssetTransactionData.getReference());
/*
* For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own (which
* would have changed their last reference) thus this is their first reference so remove it.
*/
if (assetId == Asset.QORA && Arrays.equals(recipient.getLastReference(), transferAssetTransactionData.getSignature()))
recipient.setLastReference(null);
}
}

View File

@ -1,9 +1,12 @@
package repository;
import data.assets.AssetData;
import data.assets.OrderData;
public interface AssetRepository {
// Assets
public AssetData fromAssetId(long assetId) throws DataException;
public boolean assetExists(long assetId) throws DataException;
@ -14,4 +17,8 @@ public interface AssetRepository {
public void delete(long assetId) throws DataException;
// Orders
public OrderData fromOrderId(byte[] orderId) throws DataException;
}

View File

@ -1,9 +1,11 @@
package repository.hsqldb;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import data.assets.AssetData;
import data.assets.OrderData;
import repository.AssetRepository;
import repository.DataException;
@ -15,6 +17,8 @@ public class HSQLDBAssetRepository implements AssetRepository {
this.repository = repository;
}
// Assets
public AssetData fromAssetId(long assetId) throws DataException {
try {
ResultSet resultSet = this.repository
@ -75,4 +79,27 @@ public class HSQLDBAssetRepository implements AssetRepository {
}
}
// Orders
public OrderData fromOrderId(byte[] orderId) throws DataException {
try {
ResultSet resultSet = this.repository.checkedExecute(
"SELECT creator, have_asset_id, want_asset_id, amount, fulfilled, price, timestamp FROM AssetOrders WHERE asset_order_id = ?", orderId);
if (resultSet == null)
return null;
byte[] creatorPublicKey = this.repository.getResultSetBytes(resultSet.getBinaryStream(1));
long haveAssetId = resultSet.getLong(2);
long wantAssetId = resultSet.getLong(3);
BigDecimal amount = resultSet.getBigDecimal(4);
BigDecimal fulfilled = resultSet.getBigDecimal(5);
BigDecimal price = resultSet.getBigDecimal(6);
long timestamp = resultSet.getTimestamp(7).getTime();
return new OrderData(orderId, creatorPublicKey, haveAssetId, wantAssetId, amount, fulfilled, price, timestamp);
} catch (SQLException e) {
throw new DataException("Unable to fetch order from repository", e);
}
}
}

View File

@ -90,7 +90,7 @@ public class HSQLDBDatabaseUpdates {
stmt.execute("CREATE TYPE DataHash AS VARCHAR(100)");
stmt.execute("CREATE TYPE AssetID AS BIGINT");
stmt.execute("CREATE TYPE AssetName AS VARCHAR(400) COLLATE SQL_TEXT_UCC");
stmt.execute("CREATE TYPE AssetOrderID AS VARCHAR(100)");
stmt.execute("CREATE TYPE AssetOrderID AS VARBINARY(64)");
stmt.execute("CREATE TYPE ATName AS VARCHAR(200) COLLATE SQL_TEXT_UCC");
stmt.execute("CREATE TYPE ATType AS VARCHAR(200) COLLATE SQL_TEXT_UCC");
break;
@ -227,7 +227,7 @@ public class HSQLDBDatabaseUpdates {
case 15:
// Transfer Asset Transactions
stmt.execute("CREATE TABLE TransferAssetTransactions (signature Signature, sender QoraPublicKey NOT NULL, recipient QoraAddress NOT NULL, "
+ "asset_id AssetID NOT NULL, amount QoraAmount NOT NULL, "
+ "asset_id AssetID NOT NULL, amount QoraAmount NOT NULL,"
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
break;
@ -241,7 +241,7 @@ public class HSQLDBDatabaseUpdates {
case 17:
// Cancel Asset Order Transactions
stmt.execute("CREATE TABLE CancelAssetOrderTransactions (signature Signature, creator QoraPublicKey NOT NULL, "
+ "asset_order AssetOrderID NOT NULL, "
+ "asset_order_id AssetOrderID NOT NULL, "
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
break;
@ -282,6 +282,16 @@ public class HSQLDBDatabaseUpdates {
"CREATE TABLE AccountBalances (account QoraAddress, asset_id AssetID, balance QoraAmount NOT NULL, PRIMARY KEY (account, asset_id))");
break;
case 23:
// Asset Orders
stmt.execute(
"CREATE TABLE AssetOrders (asset_order_id AssetOrderID, creator QoraPublicKey NOT NULL, have_asset_id AssetID NOT NULL, want_asset_id AssetID NOT NULL, "
+ "amount QoraAmount NOT NULL, fulfilled QoraAmount NOT NULL, price QoraAmount NOT NULL, ordered TIMESTAMP NOT NULL, "
+ "PRIMARY KEY (asset_order_id))");
stmt.execute("CREATE INDEX AssetOrderHaveIndex on AssetOrders (have_asset_id)");
stmt.execute("CREATE INDEX AssetOrderWantIndex on AssetOrders (want_asset_id)");
break;
default:
// nothing to do
return false;

View File

@ -18,8 +18,8 @@ public class HSQLDBCreateOrderTransactionRepository extends HSQLDBTransactionRep
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
try {
ResultSet rs = this.repository.checkedExecute("SELECT have_asset_id, amount, want_asset_id, price FROM CreateOrderTransactions WHERE signature = ?",
signature);
ResultSet rs = this.repository.checkedExecute(
"SELECT have_asset_id, amount, want_asset_id, price FROM CreateAssetOrderTransactions WHERE signature = ?", signature);
if (rs == null)
return null;
@ -41,7 +41,8 @@ public class HSQLDBCreateOrderTransactionRepository extends HSQLDBTransactionRep
HSQLDBSaver saveHelper = new HSQLDBSaver("CreateAssetOrderTransactions");
saveHelper.bind("signature", createOrderTransactionData.getSignature()).bind("creator", createOrderTransactionData.getCreatorPublicKey())
.bind("have_asset_id", createOrderTransactionData.getHaveAssetId()).bind("amount", createOrderTransactionData.getAmount());
.bind("have_asset_id", createOrderTransactionData.getHaveAssetId()).bind("amount", createOrderTransactionData.getAmount())
.bind("want_asset_id", createOrderTransactionData.getWantAssetId()).bind("price", createOrderTransactionData.getPrice());
try {
saveHelper.execute(this.repository);

View File

@ -237,7 +237,7 @@ public class BlockTransformer extends Transformer {
List<Trade> trades = order.getTrades();
// Filter out trades with timestamps that don't match order transaction's timestamp
trades.removeIf((Trade trade) -> trade.getTimestamp() != order.getTimestamp());
trades.removeIf((Trade trade) -> trade.getTimestamp() != order.getOrderData().getTimestamp());
// Any trades left?
if (!trades.isEmpty()) {

View File

@ -0,0 +1,107 @@
package transform.transaction;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import org.json.simple.JSONObject;
import com.google.common.hash.HashCode;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import data.transaction.TransactionData;
import data.transaction.TransferAssetTransactionData;
import qora.account.PublicKeyAccount;
import transform.TransformationException;
import utils.Base58;
import utils.Serialization;
public class TransferAssetTransactionTransformer extends TransactionTransformer {
// Property lengths
private static final int SENDER_LENGTH = PUBLIC_KEY_LENGTH;
private static final int RECIPIENT_LENGTH = ADDRESS_LENGTH;
private static final int ASSET_ID_LENGTH = LONG_LENGTH;
private static final int AMOUNT_LENGTH = 12;
private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + SENDER_LENGTH + RECIPIENT_LENGTH + ASSET_ID_LENGTH + AMOUNT_LENGTH;
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
if (byteBuffer.remaining() < TYPELESS_LENGTH)
throw new TransformationException("Byte data too short for TransferAssetTransaction");
long timestamp = byteBuffer.getLong();
byte[] reference = new byte[REFERENCE_LENGTH];
byteBuffer.get(reference);
byte[] senderPublicKey = Serialization.deserializePublicKey(byteBuffer);
String recipient = Serialization.deserializeRecipient(byteBuffer);
long assetId = byteBuffer.getLong();
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer, AMOUNT_LENGTH);
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
byte[] signature = new byte[SIGNATURE_LENGTH];
byteBuffer.get(signature);
return new TransferAssetTransactionData(senderPublicKey, recipient, amount, assetId, fee, timestamp, reference, signature);
}
public static int getDataLength(TransactionData transactionData) throws TransformationException {
return TYPE_LENGTH + TYPELESS_LENGTH;
}
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
try {
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bytes.write(Ints.toByteArray(transferAssetTransactionData.getType().value));
bytes.write(Longs.toByteArray(transferAssetTransactionData.getTimestamp()));
bytes.write(transferAssetTransactionData.getReference());
bytes.write(transferAssetTransactionData.getSenderPublicKey());
bytes.write(Base58.decode(transferAssetTransactionData.getRecipient()));
bytes.write(Longs.toByteArray(transferAssetTransactionData.getAssetId()));
Serialization.serializeBigDecimal(bytes, transferAssetTransactionData.getAmount(), AMOUNT_LENGTH);
Serialization.serializeBigDecimal(bytes, transferAssetTransactionData.getFee());
bytes.write(transferAssetTransactionData.getSignature());
return bytes.toByteArray();
} catch (IOException | ClassCastException e) {
throw new TransformationException(e);
}
}
@SuppressWarnings("unchecked")
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
JSONObject json = TransactionTransformer.getBaseJSON(transactionData);
try {
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
byte[] senderPublicKey = transferAssetTransactionData.getSenderPublicKey();
json.put("sender", PublicKeyAccount.getAddress(senderPublicKey));
json.put("senderPublicKey", HashCode.fromBytes(senderPublicKey).toString());
json.put("recipient", transferAssetTransactionData.getRecipient());
// For gen1 support:
json.put("asset", transferAssetTransactionData.getAssetId());
// Gen2 version:
json.put("assetId", transferAssetTransactionData.getAssetId());
json.put("amount", transferAssetTransactionData.getAmount().toPlainString());
} catch (ClassCastException e) {
throw new TransformationException(e);
}
return json;
}
}