forked from Qortal/qortal
Block/Transaction processing
* Add implementation for Account.getBalance(assetId, numberOfConfirmations) * Added orphan() code to Block (CIYAM AT not yet supported) * Added getOrder() 'navigation' method to CreateOrderTransaction * Added missing transaction-type cases to various switches in Transaction, transformers, repositories, etc. * Various repository delete() methods added * Added save/delete support for transaction types that include payments, like multipayment and arbitrary * Changed "recipient" in HSQLDB SharedTransactionPayments from QoraPublicKey to QoraAddress
This commit is contained in:
parent
4a1c3821db
commit
c5a32ffa1c
@ -60,7 +60,7 @@ public class Account {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// TODO - CIYAM AT support needed
|
||||
/*
|
||||
* LinkedHashMap<Tuple2<Integer, Integer>, AT_Transaction> atTxs = db.getATTransactionMap().getATTransactions(block.getHeight(db));
|
||||
* Iterator<AT_Transaction> iter = atTxs.values().iterator(); while (iter.hasNext()) { AT_Transaction key = iter.next();
|
||||
@ -80,9 +80,41 @@ public class Account {
|
||||
|
||||
// Balance manipulations - assetId is 0 for QORA
|
||||
|
||||
public BigDecimal getBalance(long assetId, int confirmations) {
|
||||
// TODO
|
||||
return null;
|
||||
public BigDecimal getBalance(long assetId, int confirmations) throws DataException {
|
||||
// Simple case: we only need balance with 1 confirmation
|
||||
if (confirmations == 1)
|
||||
return this.getConfirmedBalance(assetId);
|
||||
|
||||
/*
|
||||
* For a balance with more confirmations work back from last block, undoing transactions involving this account, until we have processed required number
|
||||
* of blocks.
|
||||
*/
|
||||
BlockRepository blockRepository = this.repository.getBlockRepository();
|
||||
BigDecimal balance = this.getConfirmedBalance(assetId);
|
||||
BlockData blockData = blockRepository.getLastBlock();
|
||||
|
||||
// Note: "blockData.getHeight() > 1" to make sure we don't examine genesis block
|
||||
for (int i = 1; i < confirmations && blockData != null && blockData.getHeight() > 1; ++i) {
|
||||
Block block = new Block(this.repository, blockData);
|
||||
|
||||
for (Transaction transaction : block.getTransactions())
|
||||
if (transaction.isInvolved(this))
|
||||
balance = balance.subtract(transaction.getAmount(this));
|
||||
|
||||
// TODO - CIYAM AT support
|
||||
/*
|
||||
* // Also check AT transactions for amounts received to this account LinkedHashMap<Tuple2<Integer, Integer>, AT_Transaction> atTxs =
|
||||
* db.getATTransactionMap().getATTransactions(block.getHeight(db)); Iterator<AT_Transaction> iter = atTxs.values().iterator(); while
|
||||
* (iter.hasNext()) { AT_Transaction key = iter.next();
|
||||
*
|
||||
* if (key.getRecipient().equals(this.getAddress())) balance = balance.subtract(BigDecimal.valueOf(key.getAmount(), 8)); }
|
||||
*/
|
||||
|
||||
blockData = block.getParent();
|
||||
}
|
||||
|
||||
// Return balance
|
||||
return balance;
|
||||
}
|
||||
|
||||
public BigDecimal getConfirmedBalance(long assetId) throws DataException {
|
||||
|
@ -5,7 +5,6 @@ import static java.util.stream.Collectors.toMap;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -609,8 +608,47 @@ public class Block {
|
||||
}
|
||||
}
|
||||
|
||||
public void orphan(Connection connection) {
|
||||
public void orphan() throws DataException {
|
||||
// TODO
|
||||
|
||||
// Orphan block's CIYAM ATs
|
||||
orphanAutomatedTransactions();
|
||||
|
||||
// Orphan transactions in reverse order, and unlink them from this block
|
||||
List<Transaction> transactions = this.getTransactions();
|
||||
for (int sequence = transactions.size() - 1; sequence >= 0; --sequence) {
|
||||
Transaction transaction = transactions.get(sequence);
|
||||
transaction.orphan();
|
||||
|
||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||
transaction.getTransactionData().getSignature());
|
||||
this.repository.getBlockRepository().delete(blockTransactionData);
|
||||
}
|
||||
|
||||
// If fees are non-zero then remove fees from generator's balance
|
||||
BigDecimal blockFee = this.blockData.getTotalFees();
|
||||
if (blockFee.compareTo(BigDecimal.ZERO) == 1)
|
||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFee));
|
||||
|
||||
// Delete block from blockchain
|
||||
this.repository.getBlockRepository().delete(this.blockData);
|
||||
}
|
||||
|
||||
public void orphanAutomatedTransactions() throws DataException {
|
||||
// TODO - CIYAM AT support
|
||||
/*
|
||||
* LinkedHashMap< Tuple2<Integer, Integer> , AT_Transaction > atTxs = DBSet.getInstance().getATTransactionMap().getATTransactions(this.getHeight(db));
|
||||
*
|
||||
* Iterator<AT_Transaction> iter = atTxs.values().iterator();
|
||||
*
|
||||
* while ( iter.hasNext() ) { AT_Transaction key = iter.next(); Long amount = key.getAmount(); if (key.getRecipientId() != null &&
|
||||
* !Arrays.equals(key.getRecipientId(), new byte[ AT_Constants.AT_ID_SIZE ]) && !key.getRecipient().equalsIgnoreCase("1") ) { Account recipient = new
|
||||
* Account( key.getRecipient() ); recipient.setConfirmedBalance( recipient.getConfirmedBalance( db ).subtract( BigDecimal.valueOf( amount, 8 ) ) , db );
|
||||
* if ( Arrays.equals(recipient.getLastReference(db),new byte[64])) { recipient.removeReference(db); } } Account sender = new Account( key.getSender()
|
||||
* ); sender.setConfirmedBalance( sender.getConfirmedBalance( db ).add( BigDecimal.valueOf( amount, 8 ) ) , db );
|
||||
*
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ public class CreateOrderTransaction extends Transaction {
|
||||
|
||||
// Navigation
|
||||
|
||||
public Order getOrder() {
|
||||
// TODO Something like:
|
||||
// return this.repository.getAssetRepository().getOrder(this.transactionData);
|
||||
return null;
|
||||
public Order getOrder() throws DataException {
|
||||
// orderId is the transaction signature
|
||||
OrderData orderData = this.repository.getAssetRepository().fromOrderId(this.createOrderTransactionData.getSignature());
|
||||
return new Order(this.repository, orderData);
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
@ -90,9 +90,18 @@ public abstract class Transaction {
|
||||
case ISSUE_ASSET:
|
||||
return new IssueAssetTransaction(repository, transactionData);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return new TransferAssetTransaction(repository, transactionData);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return new CreateOrderTransaction(repository, transactionData);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return new CancelOrderTransaction(repository, transactionData);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return new MultiPaymentTransaction(repository, transactionData);
|
||||
|
||||
case MESSAGE:
|
||||
return new MessageTransaction(repository, transactionData);
|
||||
|
||||
@ -150,6 +159,12 @@ public abstract class Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transaction version number that should be used, based on passed timestamp.
|
||||
*
|
||||
* @param timestamp
|
||||
* @return transaction version number, likely 1 or 3
|
||||
*/
|
||||
public static int getVersionByTimestamp(long timestamp) {
|
||||
if (timestamp < BlockChain.POWFIX_RELEASE_TIMESTAMP) {
|
||||
return 1;
|
||||
@ -162,9 +177,10 @@ public abstract class Transaction {
|
||||
* Get block height for this transaction in the blockchain.
|
||||
*
|
||||
* @return height, or 0 if not in blockchain (i.e. unconfirmed)
|
||||
* @throws DataException
|
||||
*/
|
||||
public int getHeight() {
|
||||
return this.repository.getTransactionRepository().getHeight(this.transactionData);
|
||||
public int getHeight() throws DataException {
|
||||
return this.repository.getTransactionRepository().getHeightFromSignature(this.transactionData.getSignature());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,7 +251,7 @@ public abstract class Transaction {
|
||||
* @throws DataException
|
||||
*/
|
||||
public BlockData getBlock() throws DataException {
|
||||
return this.repository.getTransactionRepository().toBlock(this.transactionData);
|
||||
return this.repository.getTransactionRepository().getBlockDataFromSignature(this.transactionData.getSignature());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,7 +298,6 @@ public abstract class Transaction {
|
||||
|
||||
return Arrays.copyOf(bytes, bytes.length - Transformer.SIGNATURE_LENGTH);
|
||||
} catch (TransformationException e) {
|
||||
// XXX this isn't good
|
||||
throw new RuntimeException("Unable to transform transaction to signature-less byte array", e);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,10 @@ public interface BlockRepository {
|
||||
|
||||
public void save(BlockData blockData) throws DataException;
|
||||
|
||||
public void delete(BlockData blockData) throws DataException;
|
||||
|
||||
public void save(BlockTransactionData blockTransactionData) throws DataException;
|
||||
|
||||
public void delete(BlockTransactionData blockTransactionData) throws DataException;
|
||||
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ public interface TransactionRepository {
|
||||
|
||||
public TransactionData fromReference(byte[] reference) throws DataException;
|
||||
|
||||
public int getHeight(TransactionData transactionData);
|
||||
public int getHeightFromSignature(byte[] signature) throws DataException;
|
||||
|
||||
public BlockData toBlock(TransactionData transactionData) throws DataException;
|
||||
public BlockData getBlockDataFromSignature(byte[] signature) throws DataException;
|
||||
|
||||
public void save(TransactionData transactionData) throws DataException;
|
||||
|
||||
|
@ -144,6 +144,14 @@ public class HSQLDBBlockRepository implements BlockRepository {
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(BlockData blockData) throws DataException {
|
||||
try {
|
||||
this.repository.checkedExecute("DELETE FROM Blocks WHERE signature = ?", blockData.getSignature());
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete Block from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(BlockTransactionData blockTransactionData) throws DataException {
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("BlockTransactions");
|
||||
saveHelper.bind("block_signature", blockTransactionData.getBlockSignature()).bind("sequence", blockTransactionData.getSequence())
|
||||
@ -156,4 +164,13 @@ public class HSQLDBBlockRepository implements BlockRepository {
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(BlockTransactionData blockTransactionData) throws DataException {
|
||||
try {
|
||||
this.repository.checkedExecute("DELETE FROM BlockTransactions WHERE block_signature = ? AND sequence = ? AND transaction_signature = ?",
|
||||
blockTransactionData.getBlockSignature(), blockTransactionData.getSequence(), blockTransactionData.getTransactionSignature());
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete BlockTransaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ public class HSQLDBDatabaseUpdates {
|
||||
|
||||
case 12:
|
||||
// Arbitrary/Multi-payment Transaction Payments
|
||||
stmt.execute("CREATE TABLE SharedTransactionPayments (signature Signature, recipient QoraPublicKey NOT NULL, "
|
||||
stmt.execute("CREATE TABLE SharedTransactionPayments (signature Signature, recipient QoraAddress NOT NULL, "
|
||||
+ "amount QoraAmount NOT NULL, asset_id AssetID NOT NULL, "
|
||||
+ "PRIMARY KEY (signature, recipient, asset_id), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||
break;
|
||||
|
@ -50,8 +50,6 @@ public class HSQLDBSaver {
|
||||
* Build PreparedStatement using bound column-value pairs then execute it.
|
||||
*
|
||||
* @param repository
|
||||
* TODO
|
||||
* @param repository
|
||||
*
|
||||
* @return the result from {@link PreparedStatement#execute()}
|
||||
* @throws SQLException
|
||||
|
@ -0,0 +1,49 @@
|
||||
package repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import data.transaction.CancelOrderTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import repository.DataException;
|
||||
import repository.hsqldb.HSQLDBRepository;
|
||||
import repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBCancelOrderTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBCancelOrderTransactionRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT asset_order_id FROM CancelAssetOrderTransactions WHERE signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
byte[] assetOrderId = this.repository.getResultSetBytes(rs.getBinaryStream(1));
|
||||
|
||||
return new CancelOrderTransactionData(creatorPublicKey, assetOrderId, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch cancel order transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
CancelOrderTransactionData cancelOrderTransactionData = (CancelOrderTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("CancelAssetOrderTransactions");
|
||||
|
||||
saveHelper.bind("signature", cancelOrderTransactionData.getSignature()).bind("creator", cancelOrderTransactionData.getCreatorPublicKey())
|
||||
.bind("asset_order_id", cancelOrderTransactionData.getOrderId());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save cancel order transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 CreateAssetOrderTransactions 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;
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
package repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import data.PaymentData;
|
||||
import data.transaction.MultiPaymentTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import repository.DataException;
|
||||
import repository.hsqldb.HSQLDBRepository;
|
||||
import repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBMultiPaymentTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBMultiPaymentTransactionRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT sender MultiPaymentTransactions WHERE signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
byte[] senderPublicKey = this.repository.getResultSetBytes(rs.getBinaryStream(1));
|
||||
|
||||
List<PaymentData> payments = this.getPaymentsFromSignature(signature);
|
||||
|
||||
return new MultiPaymentTransactionData(senderPublicKey, payments, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch multi-payment transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
MultiPaymentTransactionData multiPaymentTransactionData = (MultiPaymentTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("MultiPaymentTransactions");
|
||||
|
||||
saveHelper.bind("signature", multiPaymentTransactionData.getSignature()).bind("sender", multiPaymentTransactionData.getSenderPublicKey());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save multi-payment transaction into repository", e);
|
||||
}
|
||||
|
||||
// Save payments. If this fails then it is the caller's responsibility to catch the DataException as the underlying transaction will have been lost.
|
||||
this.savePayments(transactionData.getSignature(), multiPaymentTransactionData.getPayments());
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,10 @@ import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import data.PaymentData;
|
||||
import data.block.BlockData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.transaction.Transaction.TransactionType;
|
||||
@ -19,7 +22,10 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
private HSQLDBGenesisTransactionRepository genesisTransactionRepository;
|
||||
private HSQLDBPaymentTransactionRepository paymentTransactionRepository;
|
||||
private HSQLDBIssueAssetTransactionRepository issueAssetTransactionRepository;
|
||||
private HSQLDBTransferAssetTransactionRepository transferAssetTransactionRepository;
|
||||
private HSQLDBCreateOrderTransactionRepository createOrderTransactionRepository;
|
||||
private HSQLDBCancelOrderTransactionRepository cancelOrderTransactionRepository;
|
||||
private HSQLDBMultiPaymentTransactionRepository multiPaymentTransactionRepository;
|
||||
private HSQLDBMessageTransactionRepository messageTransactionRepository;
|
||||
|
||||
public HSQLDBTransactionRepository(HSQLDBRepository repository) {
|
||||
@ -27,7 +33,10 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.genesisTransactionRepository = new HSQLDBGenesisTransactionRepository(repository);
|
||||
this.paymentTransactionRepository = new HSQLDBPaymentTransactionRepository(repository);
|
||||
this.issueAssetTransactionRepository = new HSQLDBIssueAssetTransactionRepository(repository);
|
||||
this.transferAssetTransactionRepository = new HSQLDBTransferAssetTransactionRepository(repository);
|
||||
this.createOrderTransactionRepository = new HSQLDBCreateOrderTransactionRepository(repository);
|
||||
this.cancelOrderTransactionRepository = new HSQLDBCancelOrderTransactionRepository(repository);
|
||||
this.multiPaymentTransactionRepository = new HSQLDBMultiPaymentTransactionRepository(repository);
|
||||
this.messageTransactionRepository = new HSQLDBMessageTransactionRepository(repository);
|
||||
}
|
||||
|
||||
@ -82,9 +91,18 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
case ISSUE_ASSET:
|
||||
return this.issueAssetTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return this.transferAssetTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return this.createOrderTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return this.cancelOrderTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return this.multiPaymentTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case MESSAGE:
|
||||
return this.messageTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
@ -93,9 +111,46 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
}
|
||||
}
|
||||
|
||||
protected List<PaymentData> getPaymentsFromSignature(byte[] signature) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT recipient, amount, asset_id FROM SharedTransactionPayments WHERE signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
List<PaymentData> payments = new ArrayList<PaymentData>();
|
||||
|
||||
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
|
||||
do {
|
||||
String recipient = rs.getString(1);
|
||||
BigDecimal amount = rs.getBigDecimal(2);
|
||||
long assetId = rs.getLong(3);
|
||||
|
||||
payments.add(new PaymentData(recipient, assetId, amount));
|
||||
} while (rs.next());
|
||||
|
||||
return payments;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch payments from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void savePayments(byte[] signature, List<PaymentData> payments) throws DataException {
|
||||
for (PaymentData paymentData : payments) {
|
||||
HSQLDBSaver saver = new HSQLDBSaver("SharedTransactionPayments");
|
||||
|
||||
saver.bind("signature", signature).bind("recipient", paymentData.getRecipient()).bind("amount", paymentData.getAmount()).bind("asset_id",
|
||||
paymentData.getAssetId());
|
||||
|
||||
try {
|
||||
saver.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save payment into repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(TransactionData transactionData) {
|
||||
byte[] signature = transactionData.getSignature();
|
||||
public int getHeightFromSignature(byte[] signature) throws DataException {
|
||||
if (signature == null)
|
||||
return 0;
|
||||
|
||||
@ -110,13 +165,12 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
|
||||
return rs.getInt(1);
|
||||
} catch (SQLException e) {
|
||||
return 0;
|
||||
throw new DataException("Unable to fetch transaction's height from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockData toBlock(TransactionData transactionData) throws DataException {
|
||||
byte[] signature = transactionData.getSignature();
|
||||
public BlockData getBlockDataFromSignature(byte[] signature) throws DataException {
|
||||
if (signature == null)
|
||||
return null;
|
||||
|
||||
@ -143,7 +197,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
try {
|
||||
saver.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException(e);
|
||||
throw new DataException("Unable to save transaction into repository", e);
|
||||
}
|
||||
|
||||
// Now call transaction-type-specific save() method
|
||||
@ -160,10 +214,20 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.issueAssetTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
this.transferAssetTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
this.createOrderTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
this.cancelOrderTransactionRepository.save(transactionData);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
this.multiPaymentTransactionRepository.save(transactionData);
|
||||
|
||||
case MESSAGE:
|
||||
this.messageTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
@ -0,0 +1,54 @@
|
||||
package repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import data.transaction.TransferAssetTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import repository.DataException;
|
||||
import repository.hsqldb.HSQLDBRepository;
|
||||
import repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBTransferAssetTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBTransferAssetTransactionRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||
try {
|
||||
ResultSet rs = this.repository.checkedExecute("SELECT sender, recipient, asset_id, amount FROM TransferAssetTransactions WHERE signature = ?",
|
||||
signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
byte[] senderPublicKey = this.repository.getResultSetBytes(rs.getBinaryStream(1));
|
||||
String recipient = rs.getString(2);
|
||||
long assetId = rs.getLong(3);
|
||||
BigDecimal amount = rs.getBigDecimal(4);
|
||||
|
||||
return new TransferAssetTransactionData(senderPublicKey, recipient, amount, assetId, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch transfer asset transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("TransferAssetTransactions");
|
||||
|
||||
saveHelper.bind("signature", transferAssetTransactionData.getSignature()).bind("sender", transferAssetTransactionData.getSenderPublicKey())
|
||||
.bind("recipient", transferAssetTransactionData.getRecipient()).bind("asset_id", transferAssetTransactionData.getAssetId())
|
||||
.bind("amount", transferAssetTransactionData.getAmount());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save transfer asset transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ public class NavigationTests extends Common {
|
||||
assertNotNull("Transaction data not loaded from repository", transactionData);
|
||||
assertEquals("Transaction data not PAYMENT type", TransactionType.PAYMENT, transactionData.getType());
|
||||
|
||||
BlockData blockData = transactionRepository.toBlock(transactionData);
|
||||
BlockData blockData = transactionRepository.getBlockDataFromSignature(signature);
|
||||
assertNotNull("Block 49778 not loaded from database", blockData);
|
||||
|
||||
System.out.println("Block " + blockData.getHeight() + ", signature: " + Base58.encode(blockData.getSignature()));
|
||||
|
@ -29,7 +29,6 @@ import repository.Repository;
|
||||
import repository.RepositoryFactory;
|
||||
import repository.RepositoryManager;
|
||||
import repository.hsqldb.HSQLDBRepositoryFactory;
|
||||
import utils.NTP;
|
||||
|
||||
// Don't extend Common as we want to use an in-memory database
|
||||
public class TransactionTests {
|
||||
|
@ -40,9 +40,18 @@ public class TransactionTransformer extends Transformer {
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return TransferAssetTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return CreateOrderTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return CancelOrderTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return MultiPaymentTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case MESSAGE:
|
||||
return MessageTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
@ -62,9 +71,18 @@ public class TransactionTransformer extends Transformer {
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return TransferAssetTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return CreateOrderTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return CancelOrderTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return MultiPaymentTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case MESSAGE:
|
||||
return MessageTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
@ -84,9 +102,18 @@ public class TransactionTransformer extends Transformer {
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return TransferAssetTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return CreateOrderTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return CancelOrderTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return MultiPaymentTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case MESSAGE:
|
||||
return MessageTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
@ -95,22 +122,31 @@ public class TransactionTransformer extends Transformer {
|
||||
}
|
||||
}
|
||||
|
||||
public static JSONObject toJSON(TransactionData transaction) throws TransformationException {
|
||||
switch (transaction.getType()) {
|
||||
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
|
||||
switch (transactionData.getType()) {
|
||||
case GENESIS:
|
||||
return GenesisTransactionTransformer.toJSON(transaction);
|
||||
return GenesisTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case PAYMENT:
|
||||
return PaymentTransactionTransformer.toJSON(transaction);
|
||||
return PaymentTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.toJSON(transaction);
|
||||
return IssueAssetTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case TRANSFER_ASSET:
|
||||
return TransferAssetTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case CREATE_ASSET_ORDER:
|
||||
return CreateOrderTransactionTransformer.toJSON(transaction);
|
||||
return CreateOrderTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
return CancelOrderTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case MULTIPAYMENT:
|
||||
return MultiPaymentTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case MESSAGE:
|
||||
return MessageTransactionTransformer.toJSON(transaction);
|
||||
return MessageTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
default:
|
||||
throw new TransformationException("Unsupported transaction type");
|
||||
|
Loading…
x
Reference in New Issue
Block a user