diff --git a/src/data/block/Block.java b/src/data/block/Block.java new file mode 100644 index 00000000..b75d4c88 --- /dev/null +++ b/src/data/block/Block.java @@ -0,0 +1,86 @@ +package data.block; + +import java.math.BigDecimal; + +import qora.account.PublicKeyAccount; + +public class Block implements BlockData { + private int version; + private byte[] reference; + private int transactionCount; + private BigDecimal totalFees; + private byte[] transactionsSignature; + private int height; + private long timestamp; + private BigDecimal generatingBalance; + private byte[] generatorPublicKey; + private byte[] generatorSignature; + private byte[] atBytes; + private BigDecimal atFees; + + public Block(int version, byte[] reference, int transactionCount, BigDecimal totalFees, byte[] transactionsSignature, + int height, long timestamp, BigDecimal generatingBalance, byte[] generatorPublicKey, byte[] generatorSignature, + byte[] atBytes, BigDecimal atFees) + { + this.version = version; + this.reference = reference; + this.transactionCount = transactionCount; + this.totalFees = totalFees; + this.transactionsSignature = transactionsSignature; + this.height = height; + this.timestamp = timestamp; + this.generatingBalance = generatingBalance; + this.generatorPublicKey = generatorPublicKey; + this.generatorSignature = generatorSignature; + this.atBytes = atBytes; + this.atFees = atFees; + } + + public int getVersion() { + return version; + } + + public byte[] getReference() { + return reference; + } + + public int getTransactionCount() { + return transactionCount; + } + + public BigDecimal getTotalFees() { + return totalFees; + } + + public byte[] getTransactionsSignature() { + return transactionsSignature; + } + + public int getHeight() { + return height; + } + + public long getTimestamp() { + return timestamp; + } + + public BigDecimal getGeneratingBalance() { + return generatingBalance; + } + + public byte[] getGeneratorPublicKey() { + return generatorPublicKey; + } + + public byte[] getGeneratorSignature() { + return generatorSignature; + } + + public byte[] getAtBytes() { + return atBytes; + } + + public BigDecimal getAtFees() { + return atFees; + } +} diff --git a/src/data/block/BlockData.java b/src/data/block/BlockData.java new file mode 100644 index 00000000..20db7a94 --- /dev/null +++ b/src/data/block/BlockData.java @@ -0,0 +1,18 @@ +package data.block; + +import java.math.BigDecimal; + +public interface BlockData { + public int getVersion(); + public byte[] getReference(); + public int getTransactionCount(); + public BigDecimal getTotalFees(); + public byte[] getTransactionsSignature(); + public int getHeight(); + public long getTimestamp(); + public BigDecimal getGeneratingBalance(); + public byte[] getGeneratorPublicKey(); + public byte[] getGeneratorSignature(); + public byte[] getAtBytes(); + public BigDecimal getAtFees(); +} diff --git a/src/data/transaction/Transaction.java b/src/data/transaction/Transaction.java index 6b0f835c..4d722664 100644 --- a/src/data/transaction/Transaction.java +++ b/src/data/transaction/Transaction.java @@ -11,6 +11,8 @@ import static java.util.stream.Collectors.toMap; public abstract class Transaction { // Transaction types + // TODO Transaction types are semantic and should go into the business logic layer. + // No need to know the meaning of the integer value in data layer public enum TransactionType { GENESIS(1), PAYMENT(2), REGISTER_NAME(3), UPDATE_NAME(4), SELL_NAME(5), CANCEL_SELL_NAME(6), BUY_NAME(7), CREATE_POLL(8), VOTE_ON_POLL(9), ARBITRARY( 10), ISSUE_ASSET(11), TRANSFER_ASSET(12), CREATE_ASSET_ORDER(13), CANCEL_ASSET_ORDER(14), MULTIPAYMENT(15), DEPLOY_AT(16), MESSAGE(17); @@ -29,7 +31,8 @@ public abstract class Transaction { } // Properties shared with all transaction types - protected TransactionType type; + protected TransactionType type; + // TODO PublicKeyAccount is a separate data entity, so here should only be a key to reference it protected PublicKeyAccount creator; protected long timestamp; protected byte[] reference; diff --git a/src/qora/block/BlockFactory.java b/src/qora/block/BlockFactory.java index 96e5d172..bc5351db 100644 --- a/src/qora/block/BlockFactory.java +++ b/src/qora/block/BlockFactory.java @@ -1,13 +1,25 @@ package qora.block; +import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import data.block.BlockData; import database.DB; import database.NoDataFoundException; +import qora.account.PublicKeyAccount; +import qora.transaction.Transaction; +import qora.transaction.TransactionFactory; +import repository.BlockRepository; +import repository.hsqldb.HSQLDBBlockRepository; public class BlockFactory { + // XXX repository should be pushed here from the root entry, no need to know the repository type + private static BlockRepository repository = new HSQLDBBlockRepository(); + /** * Load Block from DB using block signature. * @@ -35,16 +47,23 @@ public class BlockFactory { * @return ? extends Block, or null if not found * @throws SQLException */ - public static Block fromHeight(int height) throws SQLException { + public static Block fromHeight(int height) { if (height == 1) return GenesisBlock.getInstance(); - PreparedStatement preparedStatement = DB.getConnection().prepareStatement("SELECT signature FROM Blocks WHERE height = ?"); - preparedStatement.setInt(1, height); - try { - return new Block(DB.checkedExecute(preparedStatement)); - } catch (NoDataFoundException e) { + BlockData data = repository.fromHeight(height); + + // TODO fill this list from TransactionFactory + List transactions = new ArrayList(); + + // TODO fetch account for data.getGeneratorPublicKey() + PublicKeyAccount generator = null; + + return new Block(data.getVersion(), data.getReference(), data.getTimestamp(), data.getGeneratingBalance(), + generator,data.getGeneratorSignature(),data.getTransactionsSignature(), + data.getAtBytes(), data.getAtFees(), transactions); + } catch (Exception e) { // XXX move NoDataFoundException to repository domain and use it here? return null; } } diff --git a/src/repository/BlockRepository.java b/src/repository/BlockRepository.java new file mode 100644 index 00000000..b637a667 --- /dev/null +++ b/src/repository/BlockRepository.java @@ -0,0 +1,8 @@ +package repository; + +import data.block.BlockData; + +public interface BlockRepository { + BlockData fromSignature(byte[] signature) throws DataException; + BlockData fromHeight(int height) throws DataException; +} diff --git a/src/repository/DataException.java b/src/repository/DataException.java new file mode 100644 index 00000000..7c01697c --- /dev/null +++ b/src/repository/DataException.java @@ -0,0 +1,22 @@ +package repository; + +public class DataException extends Exception { + + private static final long serialVersionUID = -3963965667288257605L; + + public DataException() {} + + public DataException(String message) + { + super(message); + } + + public DataException(String message, Throwable cause) { + super(message, cause); + } + + public DataException(Throwable cause) { + super(cause); + } + +} diff --git a/src/repository/Repository.java b/src/repository/Repository.java index 45cca751..9e97edc5 100644 --- a/src/repository/Repository.java +++ b/src/repository/Repository.java @@ -3,9 +3,13 @@ package repository; public abstract class Repository { protected TransactionRepository transactionRepository; + protected BlockRepository blockRepository; public TransactionRepository getTransactionRepository() { return this.transactionRepository; } + public BlockRepository getBlockRepository() { + return this.blockRepository; + } } diff --git a/src/repository/RepositoryManager.java b/src/repository/RepositoryManager.java index b7dd5c5b..74260444 100644 --- a/src/repository/RepositoryManager.java +++ b/src/repository/RepositoryManager.java @@ -12,4 +12,8 @@ public abstract class RepositoryManager { return repository.transactionRepository; } + public static BlockRepository getBlockRepository() { + return repository.blockRepository; + } + } diff --git a/src/repository/hsqldb/HSQLDBBlockRepository.java b/src/repository/hsqldb/HSQLDBBlockRepository.java new file mode 100644 index 00000000..c00aba58 --- /dev/null +++ b/src/repository/hsqldb/HSQLDBBlockRepository.java @@ -0,0 +1,64 @@ +package repository.hsqldb; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; + +import data.block.Block; +import data.block.BlockData; +import database.DB; +import qora.account.PublicKeyAccount; +import repository.BlockRepository; +import repository.DataException; + +public class HSQLDBBlockRepository implements BlockRepository +{ + protected static final int TRANSACTIONS_SIGNATURE_LENGTH = 64; + protected static final int GENERATOR_SIGNATURE_LENGTH = 64; + protected static final int REFERENCE_LENGTH = GENERATOR_SIGNATURE_LENGTH + TRANSACTIONS_SIGNATURE_LENGTH; + + private static final String BLOCK_DB_COLUMNS = "version, reference, transaction_count, total_fees, " + + "transactions_signature, height, generation, generating_balance, generator, generator_signature, AT_data, AT_fees"; + + public BlockData fromSignature(byte[] signature) throws DataException + { + ResultSet rs; + try { + rs = DB.checkedExecute("SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks WHERE signature = ?", signature); + } catch (SQLException e) { + throw new DataException("Error loading data from DB", e); + } + return getBlockFromResultSet(rs); + } + + public BlockData fromHeight(int height) throws DataException + { + ResultSet rs; + try { + rs = DB.checkedExecute("SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks WHERE height = ?", height); + } catch (SQLException e) { + throw new DataException("Error loading data from DB", e); + } + return getBlockFromResultSet(rs); + } + + private BlockData getBlockFromResultSet(ResultSet rs) throws DataException { + int version = rs.getInt(1); + byte[] reference = DB.getResultSetBytes(rs.getBinaryStream(2), REFERENCE_LENGTH); + int transactionCount = rs.getInt(3); + BigDecimal totalFees = rs.getBigDecimal(4); + byte[] transactionsSignature = DB.getResultSetBytes(rs.getBinaryStream(5), TRANSACTIONS_SIGNATURE_LENGTH); + int height = rs.getInt(6); + long timestamp = rs.getTimestamp(7).getTime(); + BigDecimal generatingBalance = rs.getBigDecimal(8); + byte[] generatorPublicKey = DB.getResultSetBytes(rs.getBinaryStream(9)); + byte[] generatorSignature = DB.getResultSetBytes(rs.getBinaryStream(10), GENERATOR_SIGNATURE_LENGTH); + byte[] atBytes = DB.getResultSetBytes(rs.getBinaryStream(11)); + BigDecimal atFees = rs.getBigDecimal(12); + + return new Block(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, + generatingBalance,generatorPublicKey, generatorSignature, atBytes, atFees); + } +} diff --git a/src/repository/hsqldb/HSQLDBGenesisTransaction.java b/src/repository/hsqldb/HSQLDBGenesisTransactionRepository.java similarity index 90% rename from src/repository/hsqldb/HSQLDBGenesisTransaction.java rename to src/repository/hsqldb/HSQLDBGenesisTransactionRepository.java index e7142b6d..a8d66ffa 100644 --- a/src/repository/hsqldb/HSQLDBGenesisTransaction.java +++ b/src/repository/hsqldb/HSQLDBGenesisTransactionRepository.java @@ -10,7 +10,7 @@ import data.transaction.GenesisTransaction; import data.transaction.Transaction; import database.DB; -public class HSQLDBGenesisTransaction extends HSQLDBTransaction { +public class HSQLDBGenesisTransactionRepository extends HSQLDBTransactionRepository { Transaction fromBase(byte[] signature, byte[] reference, PublicKeyAccount creator, long timestamp, BigDecimal fee) { try { diff --git a/src/repository/hsqldb/HSQLDBRepository.java b/src/repository/hsqldb/HSQLDBRepository.java index d3595507..2210d917 100644 --- a/src/repository/hsqldb/HSQLDBRepository.java +++ b/src/repository/hsqldb/HSQLDBRepository.java @@ -5,7 +5,7 @@ import repository.Repository; public class HSQLDBRepository extends Repository { public HSQLDBRepository() { - this.transactionRepository = new HSQLDBTransaction(); + this.transactionRepository = new HSQLDBTransactionRepository(); } } diff --git a/src/repository/hsqldb/HSQLDBTransaction.java b/src/repository/hsqldb/HSQLDBTransactionRepository.java similarity index 93% rename from src/repository/hsqldb/HSQLDBTransaction.java rename to src/repository/hsqldb/HSQLDBTransactionRepository.java index f4e79072..3749946e 100644 --- a/src/repository/hsqldb/HSQLDBTransaction.java +++ b/src/repository/hsqldb/HSQLDBTransactionRepository.java @@ -12,12 +12,12 @@ import database.DB; import qora.block.Block; import repository.TransactionRepository; -public class HSQLDBTransaction implements TransactionRepository { +public class HSQLDBTransactionRepository implements TransactionRepository { - private HSQLDBGenesisTransaction genesisTransactionRepository; + private HSQLDBGenesisTransactionRepository genesisTransactionRepository; - public HSQLDBTransaction() { - genesisTransactionRepository = new HSQLDBGenesisTransaction(); + public HSQLDBTransactionRepository() { + genesisTransactionRepository = new HSQLDBGenesisTransactionRepository(); } public Transaction fromSignature(byte[] signature) {