forked from Qortal/qortal
Added Create Poll Transaction support (untested)
* Moved Asset issue/deissue code from IssueAssetTransaction to Asset business object. * Added more constructors for Asset using IssueAssetTransactionData or assetId. * Moved some constants from transaction transfers to business objects (e.g. IssueAssetTransaction) (They might now make more sense being in Asset) * Changed some transaction isValid() checks to use transaction's timestamp instead of NTP.getTime() * New VotingRepository - as yet unimplemented Really need to rewrite "migrate" and add a ton of unit tests.
This commit is contained in:
parent
c5a32ffa1c
commit
5e674cbaab
53
src/data/transaction/CreatePollTransactionData.java
Normal file
53
src/data/transaction/CreatePollTransactionData.java
Normal file
@ -0,0 +1,53 @@
|
||||
package data.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import data.voting.PollOptionData;
|
||||
import qora.transaction.Transaction;
|
||||
|
||||
public class CreatePollTransactionData extends TransactionData {
|
||||
|
||||
// Properties
|
||||
private byte[] creatorPublicKey;
|
||||
private String owner;
|
||||
private String pollName;
|
||||
private String description;
|
||||
private List<PollOptionData> pollOptions;
|
||||
|
||||
// Constructors
|
||||
|
||||
public CreatePollTransactionData(byte[] creatorPublicKey, String owner, String pollName, String description, List<PollOptionData> pollOptions,
|
||||
BigDecimal fee, long timestamp, byte[] reference, byte[] signature) {
|
||||
super(Transaction.TransactionType.CREATE_POLL, fee, creatorPublicKey, timestamp, reference, signature);
|
||||
|
||||
this.creatorPublicKey = creatorPublicKey;
|
||||
this.owner = owner;
|
||||
this.pollName = pollName;
|
||||
this.description = description;
|
||||
this.pollOptions = pollOptions;
|
||||
}
|
||||
|
||||
// Getters/setters
|
||||
|
||||
public byte[] getCreatorPublicKey() {
|
||||
return this.creatorPublicKey;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public String getPollName() {
|
||||
return this.pollName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public List<PollOptionData> getPollOptions() {
|
||||
return this.pollOptions;
|
||||
}
|
||||
|
||||
}
|
47
src/data/voting/PollData.java
Normal file
47
src/data/voting/PollData.java
Normal file
@ -0,0 +1,47 @@
|
||||
package data.voting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import data.voting.PollOptionData;
|
||||
|
||||
public class PollData {
|
||||
|
||||
// Properties
|
||||
private byte[] creatorPublicKey;
|
||||
private String owner;
|
||||
private String pollName;
|
||||
private String description;
|
||||
private List<PollOptionData> pollOptions;
|
||||
|
||||
// Constructors
|
||||
|
||||
public PollData(byte[] creatorPublicKey, String owner, String pollName, String description, List<PollOptionData> pollOptions) {
|
||||
this.creatorPublicKey = creatorPublicKey;
|
||||
this.pollName = pollName;
|
||||
this.description = description;
|
||||
this.pollOptions = pollOptions;
|
||||
}
|
||||
|
||||
// Getters/setters
|
||||
|
||||
public byte[] getCreatorPublicKey() {
|
||||
return this.creatorPublicKey;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
public String getPollName() {
|
||||
return this.pollName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public List<PollOptionData> getPollOptions() {
|
||||
return this.pollOptions;
|
||||
}
|
||||
|
||||
}
|
20
src/data/voting/PollOptionData.java
Normal file
20
src/data/voting/PollOptionData.java
Normal file
@ -0,0 +1,20 @@
|
||||
package data.voting;
|
||||
|
||||
public class PollOptionData {
|
||||
|
||||
// Properties
|
||||
private String optionName;
|
||||
|
||||
// Constructors
|
||||
|
||||
public PollOptionData(String optionName) {
|
||||
this.optionName = optionName;
|
||||
}
|
||||
|
||||
// Getters/setters
|
||||
|
||||
public String getOptionName() {
|
||||
return this.optionName;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package qora.assets;
|
||||
|
||||
import data.assets.AssetData;
|
||||
import data.transaction.IssueAssetTransactionData;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
|
||||
public class Asset {
|
||||
@ -21,4 +23,32 @@ public class Asset {
|
||||
this.assetData = assetData;
|
||||
}
|
||||
|
||||
public Asset(Repository repository, IssueAssetTransactionData issueAssetTransactionData) {
|
||||
this.repository = repository;
|
||||
this.assetData = new AssetData(issueAssetTransactionData.getOwner(), issueAssetTransactionData.getAssetName(),
|
||||
issueAssetTransactionData.getDescription(), issueAssetTransactionData.getQuantity(), issueAssetTransactionData.getIsDivisible(),
|
||||
issueAssetTransactionData.getReference());
|
||||
}
|
||||
|
||||
public Asset(Repository repository, long assetId) throws DataException {
|
||||
this.repository = repository;
|
||||
this.assetData = this.repository.getAssetRepository().fromAssetId(assetId);
|
||||
}
|
||||
|
||||
// Getters/setters
|
||||
|
||||
public AssetData getAssetData() {
|
||||
return this.assetData;
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
public void issue() throws DataException {
|
||||
this.repository.getAssetRepository().save(this.assetData);
|
||||
}
|
||||
|
||||
public void deissue() throws DataException {
|
||||
this.repository.getAssetRepository().delete(this.assetData.getAssetId());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public class BlockChain {
|
||||
public static final int AT_BLOCK_HEIGHT_RELEASE = 99000;
|
||||
public static final long POWFIX_RELEASE_TIMESTAMP = 1456426800000L; // Block Version 3 // 2016-02-25T19:00:00+00:00
|
||||
public static final long ASSETS_RELEASE_TIMESTAMP = 0L; // From Qora epoch
|
||||
|
||||
public static final long VOTING_RELEASE_TIMESTAMP = 1403715600000L; // 2014-06-25T17:00:00+00:00
|
||||
|
||||
/**
|
||||
* Some sort start-up/initialization/checking method.
|
||||
|
183
src/qora/transaction/CreatePollTransaction.java
Normal file
183
src/qora/transaction/CreatePollTransaction.java
Normal file
@ -0,0 +1,183 @@
|
||||
package qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import data.transaction.CreatePollTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import data.voting.PollOptionData;
|
||||
import qora.account.Account;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.assets.Asset;
|
||||
import qora.block.BlockChain;
|
||||
import qora.crypto.Crypto;
|
||||
import qora.voting.Poll;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
|
||||
public class CreatePollTransaction extends Transaction {
|
||||
|
||||
// Properties
|
||||
private CreatePollTransactionData createPollTransactionData;
|
||||
|
||||
// Other useful constants
|
||||
public static final int MAX_NAME_SIZE = 400;
|
||||
public static final int MAX_DESCRIPTION_SIZE = 4000;
|
||||
public static final int MAX_OPTIONS = 100;
|
||||
|
||||
// Constructors
|
||||
|
||||
public CreatePollTransaction(Repository repository, TransactionData transactionData) {
|
||||
super(repository, transactionData);
|
||||
|
||||
this.createPollTransactionData = (CreatePollTransactionData) this.transactionData;
|
||||
}
|
||||
|
||||
// More information
|
||||
|
||||
public List<Account> getRecipientAccounts() throws DataException {
|
||||
return Collections.singletonList(getOwner());
|
||||
}
|
||||
|
||||
public boolean isInvolved(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
|
||||
if (address.equals(this.getCreator().getAddress()))
|
||||
return true;
|
||||
|
||||
if (address.equals(this.getOwner().getAddress()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
BigDecimal amount = BigDecimal.ZERO.setScale(8);
|
||||
|
||||
if (address.equals(this.getCreator().getAddress()))
|
||||
amount = amount.subtract(this.transactionData.getFee());
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getCreator() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, this.createPollTransactionData.getCreatorPublicKey());
|
||||
}
|
||||
|
||||
public Account getOwner() throws DataException {
|
||||
return new Account(this.repository, this.createPollTransactionData.getOwner());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are CreatePollTransactions even allowed at this point?
|
||||
// XXX In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used?
|
||||
if (this.createPollTransactionData.getTimestamp() < BlockChain.VOTING_RELEASE_TIMESTAMP)
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check owner address is valid
|
||||
if (!Crypto.isValidAddress(createPollTransactionData.getOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
|
||||
// Check name size bounds
|
||||
if (createPollTransactionData.getPollName().length() < 1 || createPollTransactionData.getPollName().length() > CreatePollTransaction.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check description size bounds
|
||||
if (createPollTransactionData.getDescription().length() < 1
|
||||
|| createPollTransactionData.getDescription().length() > CreatePollTransaction.MAX_DESCRIPTION_SIZE)
|
||||
return ValidationResult.INVALID_DESCRIPTION_LENGTH;
|
||||
|
||||
// Check poll name is lowercase
|
||||
if (!createPollTransactionData.getPollName().equals(createPollTransactionData.getPollName().toLowerCase()))
|
||||
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||
|
||||
// Check the poll name isn't already taken
|
||||
if (this.repository.getVotingRepository().pollExists(createPollTransactionData.getPollName()))
|
||||
return ValidationResult.POLL_ALREADY_EXISTS;
|
||||
|
||||
// XXX In gen1 we tested for votes but how can there be any if poll doesn't exist?
|
||||
|
||||
// Check number of options
|
||||
List<PollOptionData> pollOptions = createPollTransactionData.getPollOptions();
|
||||
int pollOptionsCount = pollOptions.size();
|
||||
if (pollOptionsCount < 1 || pollOptionsCount > MAX_OPTIONS)
|
||||
return ValidationResult.INVALID_OPTIONS_COUNT;
|
||||
|
||||
// Check each option
|
||||
List<String> optionNames = new ArrayList<String>();
|
||||
for (PollOptionData pollOptionData : pollOptions) {
|
||||
// Check option length
|
||||
int optionNameLength = pollOptionData.getOptionName().getBytes(StandardCharsets.UTF_8).length;
|
||||
if (optionNameLength < 1 || optionNameLength > MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_OPTION_LENGTH;
|
||||
|
||||
// Check option is unique. NOTE: NOT case-sensitive!
|
||||
if (optionNames.contains(pollOptionData.getOptionName())) {
|
||||
return ValidationResult.DUPLICATE_OPTION;
|
||||
}
|
||||
|
||||
optionNames.add(pollOptionData.getOptionName());
|
||||
}
|
||||
|
||||
// Check fee is positive
|
||||
if (createPollTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
// Check reference is correct
|
||||
PublicKeyAccount creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
|
||||
if (!Arrays.equals(creator.getLastReference(), createPollTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check issuer has enough funds
|
||||
if (creator.getConfirmedBalance(Asset.QORA).compareTo(createPollTransactionData.getFee()) == -1)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Publish poll to allow voting
|
||||
Poll poll = new Poll(this.repository, createPollTransactionData);
|
||||
poll.publish();
|
||||
|
||||
// Save this transaction, now with corresponding pollId
|
||||
this.repository.getTransactionRepository().save(createPollTransactionData);
|
||||
|
||||
// Update creator's balance
|
||||
Account creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).subtract(createPollTransactionData.getFee()));
|
||||
|
||||
// Update creator's reference
|
||||
creator.setLastReference(createPollTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Unpublish poll
|
||||
Poll poll = new Poll(this.repository, createPollTransactionData.getPollName());
|
||||
poll.unpublish();
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(createPollTransactionData);
|
||||
|
||||
// Update issuer's balance
|
||||
Account creator = new PublicKeyAccount(this.repository, createPollTransactionData.getCreatorPublicKey());
|
||||
creator.setConfirmedBalance(Asset.QORA, creator.getConfirmedBalance(Asset.QORA).add(createPollTransactionData.getFee()));
|
||||
|
||||
// Update issuer's reference
|
||||
creator.setLastReference(createPollTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,6 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import data.assets.AssetData;
|
||||
import data.transaction.IssueAssetTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.Account;
|
||||
@ -15,14 +14,16 @@ import qora.block.BlockChain;
|
||||
import qora.crypto.Crypto;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import transform.transaction.IssueAssetTransactionTransformer;
|
||||
import utils.NTP;
|
||||
|
||||
public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
// Properties
|
||||
private IssueAssetTransactionData issueAssetTransactionData;
|
||||
|
||||
// Other useful constants
|
||||
public static final int MAX_NAME_SIZE = 400;
|
||||
public static final int MAX_DESCRIPTION_SIZE = 4000;
|
||||
|
||||
// Constructors
|
||||
|
||||
public IssueAssetTransaction(Repository repository, TransactionData transactionData) {
|
||||
@ -75,7 +76,8 @@ public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are IssueAssetTransactions even allowed at this point?
|
||||
if (NTP.getTime() < BlockChain.ASSETS_RELEASE_TIMESTAMP)
|
||||
// XXX In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used?
|
||||
if (this.issueAssetTransactionData.getTimestamp() < BlockChain.ASSETS_RELEASE_TIMESTAMP)
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check owner address is valid
|
||||
@ -83,13 +85,12 @@ public class IssueAssetTransaction extends Transaction {
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
|
||||
// Check name size bounds
|
||||
if (issueAssetTransactionData.getAssetName().length() < 1
|
||||
|| issueAssetTransactionData.getAssetName().length() > IssueAssetTransactionTransformer.MAX_NAME_SIZE)
|
||||
if (issueAssetTransactionData.getAssetName().length() < 1 || issueAssetTransactionData.getAssetName().length() > IssueAssetTransaction.MAX_NAME_SIZE)
|
||||
return ValidationResult.INVALID_NAME_LENGTH;
|
||||
|
||||
// Check description size bounds
|
||||
if (issueAssetTransactionData.getDescription().length() < 1
|
||||
|| issueAssetTransactionData.getDescription().length() > IssueAssetTransactionTransformer.MAX_DESCRIPTION_SIZE)
|
||||
|| issueAssetTransactionData.getDescription().length() > IssueAssetTransaction.MAX_DESCRIPTION_SIZE)
|
||||
return ValidationResult.INVALID_DESCRIPTION_LENGTH;
|
||||
|
||||
// Check quantity - either 10 billion or if that's not enough: a billion billion!
|
||||
@ -120,13 +121,11 @@ public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
public void process() throws DataException {
|
||||
// Issue asset
|
||||
AssetData assetData = new AssetData(issueAssetTransactionData.getOwner(), issueAssetTransactionData.getAssetName(),
|
||||
issueAssetTransactionData.getDescription(), issueAssetTransactionData.getQuantity(), issueAssetTransactionData.getIsDivisible(),
|
||||
issueAssetTransactionData.getReference());
|
||||
this.repository.getAssetRepository().save(assetData);
|
||||
Asset asset = new Asset(this.repository, issueAssetTransactionData);
|
||||
asset.issue();
|
||||
|
||||
// Note newly assigned asset ID in our transaction record
|
||||
issueAssetTransactionData.setAssetId(assetData.getAssetId());
|
||||
issueAssetTransactionData.setAssetId(asset.getAssetData().getAssetId());
|
||||
|
||||
// Save this transaction, now with corresponding assetId
|
||||
this.repository.getTransactionRepository().save(issueAssetTransactionData);
|
||||
@ -148,8 +147,9 @@ public class IssueAssetTransaction extends Transaction {
|
||||
Account owner = new Account(this.repository, issueAssetTransactionData.getOwner());
|
||||
owner.deleteBalance(issueAssetTransactionData.getAssetId());
|
||||
|
||||
// Unissue asset
|
||||
this.repository.getAssetRepository().delete(issueAssetTransactionData.getAssetId());
|
||||
// Issue asset
|
||||
Asset asset = new Asset(this.repository, issueAssetTransactionData.getAssetId());
|
||||
asset.deissue();
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(issueAssetTransactionData);
|
||||
|
@ -21,8 +21,8 @@ public class MessageTransaction extends Transaction {
|
||||
// Properties
|
||||
private MessageTransactionData messageTransactionData;
|
||||
|
||||
// Useful constants
|
||||
private static final int MAX_DATA_SIZE = 4000;
|
||||
// Other useful constants
|
||||
public static final int MAX_DATA_SIZE = 4000;
|
||||
|
||||
// Constructors
|
||||
|
||||
|
@ -44,9 +44,10 @@ 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_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), ORDER_DOES_NOT_EXIST(32), INVALID_ORDER_CREATOR(
|
||||
33), INVALID_PAYMENTS_COUNT(34), NEGATIVE_PRICE(35), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
|
||||
15), NAME_NOT_LOWER_CASE(17), INVALID_DESCRIPTION_LENGTH(18), INVALID_OPTIONS_COUNT(19), INVALID_OPTION_LENGTH(20), DUPLICATE_OPTION(
|
||||
21), POLL_ALREADY_EXISTS(22), INVALID_DATA_LENGTH(27), INVALID_QUANTITY(28), ASSET_DOES_NOT_EXIST(29), INVALID_RETURN(
|
||||
30), HAVE_EQUALS_WANT(31), ORDER_DOES_NOT_EXIST(32), INVALID_ORDER_CREATOR(
|
||||
33), INVALID_PAYMENTS_COUNT(34), NEGATIVE_PRICE(35), ASSET_ALREADY_EXISTS(43), NOT_YET_RELEASED(1000);
|
||||
|
||||
public final int value;
|
||||
|
||||
@ -87,6 +88,9 @@ public abstract class Transaction {
|
||||
case PAYMENT:
|
||||
return new PaymentTransaction(repository, transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return new CreatePollTransaction(repository, transactionData);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return new IssueAssetTransaction(repository, transactionData);
|
||||
|
||||
|
53
src/qora/voting/Poll.java
Normal file
53
src/qora/voting/Poll.java
Normal file
@ -0,0 +1,53 @@
|
||||
package qora.voting;
|
||||
|
||||
import data.transaction.CreatePollTransactionData;
|
||||
import data.voting.PollData;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
|
||||
public class Poll {
|
||||
|
||||
// Properties
|
||||
private Repository repository;
|
||||
private PollData pollData;
|
||||
|
||||
// Constructors
|
||||
|
||||
public Poll(Repository repository, PollData pollData) {
|
||||
this.repository = repository;
|
||||
this.pollData = pollData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Poll business object using info from create poll transaction.
|
||||
*
|
||||
* @param repository
|
||||
* @param createPollTransactionData
|
||||
*/
|
||||
public Poll(Repository repository, CreatePollTransactionData createPollTransactionData) {
|
||||
this.repository = repository;
|
||||
this.pollData = new PollData(createPollTransactionData.getCreatorPublicKey(), createPollTransactionData.getOwner(),
|
||||
createPollTransactionData.getPollName(), createPollTransactionData.getDescription(), createPollTransactionData.getPollOptions());
|
||||
}
|
||||
|
||||
public Poll(Repository repository, String pollName) throws DataException {
|
||||
this.repository = repository;
|
||||
this.pollData = this.repository.getVotingRepository().fromPollName(pollName);
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
/**
|
||||
* "Publish" poll to allow voting.
|
||||
*
|
||||
* @throws DataException
|
||||
*/
|
||||
public void publish() throws DataException {
|
||||
this.repository.getVotingRepository().save(this.pollData);
|
||||
}
|
||||
|
||||
public void unpublish() throws DataException {
|
||||
this.repository.getVotingRepository().delete(this.pollData.getPollName());
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,8 @@ public interface Repository extends AutoCloseable {
|
||||
|
||||
public TransactionRepository getTransactionRepository();
|
||||
|
||||
public VotingRepository getVotingRepository();
|
||||
|
||||
public void saveChanges() throws DataException;
|
||||
|
||||
public void discardChanges() throws DataException;
|
||||
|
15
src/repository/VotingRepository.java
Normal file
15
src/repository/VotingRepository.java
Normal file
@ -0,0 +1,15 @@
|
||||
package repository;
|
||||
|
||||
import data.voting.PollData;
|
||||
|
||||
public interface VotingRepository {
|
||||
|
||||
public PollData fromPollName(String pollName) throws DataException;
|
||||
|
||||
public boolean pollExists(String pollName) throws DataException;
|
||||
|
||||
public void save(PollData pollData) throws DataException;
|
||||
|
||||
public void delete(String pollName) throws DataException;
|
||||
|
||||
}
|
@ -183,8 +183,8 @@ public class HSQLDBDatabaseUpdates {
|
||||
|
||||
case 10:
|
||||
// Create Poll Transactions
|
||||
stmt.execute("CREATE TABLE CreatePollTransactions (signature Signature, creator QoraPublicKey NOT NULL, poll PollName NOT NULL, "
|
||||
+ "description VARCHAR(4000) NOT NULL, "
|
||||
stmt.execute("CREATE TABLE CreatePollTransactions (signature Signature, creator QoraPublicKey NOT NULL, owner QoraAddress NOT NULL, "
|
||||
+ "poll PollName NOT NULL, description VARCHAR(4000) NOT NULL, "
|
||||
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||
// Poll options. NB: option is implicitly NON NULL and UNIQUE due to being part of compound primary key
|
||||
stmt.execute("CREATE TABLE CreatePollTransactionOptions (signature Signature, option PollOption, "
|
||||
@ -270,7 +270,7 @@ public class HSQLDBDatabaseUpdates {
|
||||
case 21:
|
||||
// Assets (including QORA coin itself)
|
||||
stmt.execute(
|
||||
"CREATE TABLE Assets (asset_id AssetID IDENTITY, owner QoraPublicKey NOT NULL, asset_name AssetName NOT NULL, description VARCHAR(4000) NOT NULL, "
|
||||
"CREATE TABLE Assets (asset_id AssetID IDENTITY, owner QoraAddress NOT NULL, asset_name AssetName NOT NULL, description VARCHAR(4000) NOT NULL, "
|
||||
+ "quantity BIGINT NOT NULL, is_divisible BOOLEAN NOT NULL, reference Signature NOT NULL)");
|
||||
stmt.execute("CREATE INDEX AssetNameIndex on Assets (asset_name)");
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@ import repository.BlockRepository;
|
||||
import repository.DataException;
|
||||
import repository.Repository;
|
||||
import repository.TransactionRepository;
|
||||
import repository.VotingRepository;
|
||||
import repository.hsqldb.transaction.HSQLDBTransactionRepository;
|
||||
|
||||
public class HSQLDBRepository implements Repository {
|
||||
@ -46,6 +47,11 @@ public class HSQLDBRepository implements Repository {
|
||||
return new HSQLDBTransactionRepository(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VotingRepository getVotingRepository() {
|
||||
return new HSQLDBVotingRepository(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChanges() throws DataException {
|
||||
try {
|
||||
|
33
src/repository/hsqldb/HSQLDBVotingRepository.java
Normal file
33
src/repository/hsqldb/HSQLDBVotingRepository.java
Normal file
@ -0,0 +1,33 @@
|
||||
package repository.hsqldb;
|
||||
|
||||
import data.voting.PollData;
|
||||
import repository.VotingRepository;
|
||||
import repository.DataException;
|
||||
|
||||
public class HSQLDBVotingRepository implements VotingRepository {
|
||||
|
||||
protected HSQLDBRepository repository;
|
||||
|
||||
public HSQLDBVotingRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public PollData fromPollName(String pollName) throws DataException {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean pollExists(String pollName) throws DataException {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
public void save(PollData pollData) throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void delete(String pollName) throws DataException {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import data.transaction.CreatePollTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import data.voting.PollOptionData;
|
||||
import repository.DataException;
|
||||
import repository.hsqldb.HSQLDBRepository;
|
||||
import repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBCreatePollTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBCreatePollTransactionRepository(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 owner, poll_name, description FROM CreatePollTransactions WHERE signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
String owner = rs.getString(1);
|
||||
String pollName = rs.getString(2);
|
||||
String description = rs.getString(3);
|
||||
|
||||
rs = this.repository.checkedExecute("SELECT option_name FROM CreatePollTransactionOptions where signature = ?", signature);
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
List<PollOptionData> pollOptions = new ArrayList<PollOptionData>();
|
||||
|
||||
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
|
||||
do {
|
||||
String optionName = rs.getString(1);
|
||||
|
||||
pollOptions.add(new PollOptionData(optionName));
|
||||
} while (rs.next());
|
||||
|
||||
return new CreatePollTransactionData(creatorPublicKey, owner, pollName, description, pollOptions, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch create poll transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
CreatePollTransactionData createPollTransactionData = (CreatePollTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("CreatePollTransactions");
|
||||
|
||||
saveHelper.bind("signature", createPollTransactionData.getSignature()).bind("creator", createPollTransactionData.getCreatorPublicKey())
|
||||
.bind("owner", createPollTransactionData.getOwner()).bind("poll_name", createPollTransactionData.getPollName())
|
||||
.bind("description", createPollTransactionData.getDescription());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save create poll transaction into repository", e);
|
||||
}
|
||||
|
||||
// Now attempt to save poll options
|
||||
for (PollOptionData pollOptionData : createPollTransactionData.getPollOptions()) {
|
||||
HSQLDBSaver optionSaveHelper = new HSQLDBSaver("CreatePollTransactionOptions");
|
||||
|
||||
optionSaveHelper.bind("signature", createPollTransactionData.getSignature()).bind("option_name", pollOptionData.getOptionName());
|
||||
|
||||
try {
|
||||
optionSaveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save create poll transaction option into repository", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
protected HSQLDBRepository repository;
|
||||
private HSQLDBGenesisTransactionRepository genesisTransactionRepository;
|
||||
private HSQLDBPaymentTransactionRepository paymentTransactionRepository;
|
||||
private HSQLDBCreatePollTransactionRepository createPollTransactionRepository;
|
||||
private HSQLDBIssueAssetTransactionRepository issueAssetTransactionRepository;
|
||||
private HSQLDBTransferAssetTransactionRepository transferAssetTransactionRepository;
|
||||
private HSQLDBCreateOrderTransactionRepository createOrderTransactionRepository;
|
||||
@ -32,6 +33,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.repository = repository;
|
||||
this.genesisTransactionRepository = new HSQLDBGenesisTransactionRepository(repository);
|
||||
this.paymentTransactionRepository = new HSQLDBPaymentTransactionRepository(repository);
|
||||
this.createPollTransactionRepository = new HSQLDBCreatePollTransactionRepository(repository);
|
||||
this.issueAssetTransactionRepository = new HSQLDBIssueAssetTransactionRepository(repository);
|
||||
this.transferAssetTransactionRepository = new HSQLDBTransferAssetTransactionRepository(repository);
|
||||
this.createOrderTransactionRepository = new HSQLDBCreateOrderTransactionRepository(repository);
|
||||
@ -88,6 +90,9 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
case PAYMENT:
|
||||
return this.paymentTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case CREATE_POLL:
|
||||
return this.createPollTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return this.issueAssetTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
@ -210,6 +215,10 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.paymentTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case CREATE_POLL:
|
||||
this.createPollTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case ISSUE_ASSET:
|
||||
this.issueAssetTransactionRepository.save(transactionData);
|
||||
break;
|
||||
@ -224,9 +233,11 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
|
||||
case CANCEL_ASSET_ORDER:
|
||||
this.cancelOrderTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case MULTIPAYMENT:
|
||||
this.multiPaymentTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case MESSAGE:
|
||||
this.messageTransactionRepository.save(transactionData);
|
||||
|
151
src/transform/transaction/CreatePollTransactionTransformer.java
Normal file
151
src/transform/transaction/CreatePollTransactionTransformer.java
Normal file
@ -0,0 +1,151 @@
|
||||
package transform.transaction;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
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.CreatePollTransactionData;
|
||||
import data.transaction.TransactionData;
|
||||
import data.voting.PollOptionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.transaction.CreatePollTransaction;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
import utils.Serialization;
|
||||
|
||||
public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
// Property lengths
|
||||
private static final int OWNER_LENGTH = ADDRESS_LENGTH;
|
||||
private static final int NAME_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int DESCRIPTION_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int OPTIONS_SIZE_LENGTH = INT_LENGTH;
|
||||
|
||||
private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_DATALESS_LENGTH)
|
||||
throw new TransformationException("Byte data too short for CreatePollTransaction");
|
||||
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] creatorPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String owner = Serialization.deserializeRecipient(byteBuffer);
|
||||
|
||||
String pollName = Serialization.deserializeSizedString(byteBuffer, CreatePollTransaction.MAX_NAME_SIZE);
|
||||
String description = Serialization.deserializeSizedString(byteBuffer, CreatePollTransaction.MAX_DESCRIPTION_SIZE);
|
||||
|
||||
// Make sure there are enough bytes left for poll options
|
||||
if (byteBuffer.remaining() < OPTIONS_SIZE_LENGTH)
|
||||
throw new TransformationException("Byte data too short for CreatePollTransaction");
|
||||
|
||||
int optionsCount = byteBuffer.getInt();
|
||||
if (optionsCount < 1 || optionsCount > CreatePollTransaction.MAX_OPTIONS)
|
||||
throw new TransformationException("Invalid number of options for CreatePollTransaction");
|
||||
|
||||
List<PollOptionData> pollOptions = new ArrayList<PollOptionData>();
|
||||
for (int i = 0; i < optionsCount; ++i) {
|
||||
String optionName = Serialization.deserializeSizedString(byteBuffer, CreatePollTransaction.MAX_NAME_SIZE);
|
||||
|
||||
pollOptions.add(new PollOptionData(optionName));
|
||||
}
|
||||
|
||||
// Still need to make sure there are enough bytes left for remaining fields
|
||||
if (byteBuffer.remaining() < FEE_LENGTH + SIGNATURE_LENGTH)
|
||||
throw new TransformationException("Byte data too short for CreatePollTransaction");
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new CreatePollTransactionData(creatorPublicKey, owner, pollName, description, pollOptions, fee, timestamp, reference, signature);
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
CreatePollTransactionData createPollTransactionData = (CreatePollTransactionData) transactionData;
|
||||
|
||||
int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + createPollTransactionData.getPollName().length();
|
||||
|
||||
// Add lengths for each poll options
|
||||
for (PollOptionData pollOptionData : createPollTransactionData.getPollOptions())
|
||||
dataLength += OPTIONS_SIZE_LENGTH + pollOptionData.getOptionName().length();
|
||||
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
try {
|
||||
CreatePollTransactionData createPollTransactionData = (CreatePollTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(createPollTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(createPollTransactionData.getTimestamp()));
|
||||
bytes.write(createPollTransactionData.getReference());
|
||||
|
||||
bytes.write(createPollTransactionData.getCreatorPublicKey());
|
||||
bytes.write(Base58.decode(createPollTransactionData.getOwner()));
|
||||
Serialization.serializeSizedString(bytes, createPollTransactionData.getPollName());
|
||||
Serialization.serializeSizedString(bytes, createPollTransactionData.getDescription());
|
||||
|
||||
List<PollOptionData> pollOptions = createPollTransactionData.getPollOptions();
|
||||
bytes.write(Ints.toByteArray(pollOptions.size()));
|
||||
|
||||
for (PollOptionData pollOptionData : pollOptions) {
|
||||
Serialization.serializeSizedString(bytes, pollOptionData.getOptionName());
|
||||
}
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, createPollTransactionData.getFee());
|
||||
bytes.write(createPollTransactionData.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 {
|
||||
CreatePollTransactionData createPollTransactionData = (CreatePollTransactionData) transactionData;
|
||||
|
||||
byte[] creatorPublicKey = createPollTransactionData.getCreatorPublicKey();
|
||||
|
||||
json.put("creator", PublicKeyAccount.getAddress(creatorPublicKey));
|
||||
json.put("creatorPublicKey", HashCode.fromBytes(creatorPublicKey).toString());
|
||||
|
||||
json.put("owner", createPollTransactionData.getOwner());
|
||||
json.put("name", createPollTransactionData.getPollName());
|
||||
json.put("description", createPollTransactionData.getDescription());
|
||||
|
||||
JSONArray options = new JSONArray();
|
||||
for (PollOptionData optionData : createPollTransactionData.getPollOptions()) {
|
||||
options.add(optionData.getOptionName());
|
||||
}
|
||||
|
||||
json.put("options", options);
|
||||
} catch (ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,7 @@ import com.google.common.primitives.Longs;
|
||||
|
||||
import data.transaction.TransactionData;
|
||||
import qora.account.PublicKeyAccount;
|
||||
import qora.transaction.IssueAssetTransaction;
|
||||
import data.transaction.IssueAssetTransactionData;
|
||||
import transform.TransformationException;
|
||||
import utils.Base58;
|
||||
@ -31,10 +32,6 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + ISSUER_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH
|
||||
+ QUANTITY_LENGTH + IS_DIVISIBLE_LENGTH;
|
||||
|
||||
// Other useful lengths
|
||||
public static final int MAX_NAME_SIZE = 400;
|
||||
public static final int MAX_DESCRIPTION_SIZE = 4000;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_LENGTH)
|
||||
throw new TransformationException("Byte data too short for IssueAssetTransaction");
|
||||
@ -47,11 +44,11 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
byte[] issuerPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
String owner = Serialization.deserializeRecipient(byteBuffer);
|
||||
|
||||
String assetName = Serialization.deserializeSizedString(byteBuffer, MAX_NAME_SIZE);
|
||||
String description = Serialization.deserializeSizedString(byteBuffer, MAX_DESCRIPTION_SIZE);
|
||||
String assetName = Serialization.deserializeSizedString(byteBuffer, IssueAssetTransaction.MAX_NAME_SIZE);
|
||||
String description = Serialization.deserializeSizedString(byteBuffer, IssueAssetTransaction.MAX_DESCRIPTION_SIZE);
|
||||
|
||||
// Still need to make sure there are enough bytes left for remaining fields
|
||||
if (byteBuffer.remaining() < QUANTITY_LENGTH + IS_DIVISIBLE_LENGTH + SIGNATURE_LENGTH)
|
||||
if (byteBuffer.remaining() < QUANTITY_LENGTH + IS_DIVISIBLE_LENGTH + FEE_LENGTH + SIGNATURE_LENGTH)
|
||||
throw new TransformationException("Byte data too short for IssueAssetTransaction");
|
||||
|
||||
long quantity = byteBuffer.getLong();
|
||||
|
@ -37,9 +37,6 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
private static final int TYPELESS_DATALESS_LENGTH_V3 = BASE_TYPELESS_LENGTH + SENDER_LENGTH + RECIPIENT_LENGTH + ASSET_ID_LENGTH + AMOUNT_LENGTH
|
||||
+ DATA_SIZE_LENGTH + IS_TEXT_LENGTH + IS_ENCRYPTED_LENGTH;
|
||||
|
||||
// Other property lengths
|
||||
private static final int MAX_DATA_SIZE = 4000;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
if (byteBuffer.remaining() < TYPELESS_DATALESS_LENGTH_V1)
|
||||
throw new TransformationException("Byte data too short for MessageTransaction");
|
||||
@ -69,12 +66,16 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int dataSize = byteBuffer.getInt(0);
|
||||
// Don't allow invalid dataSize here to avoid run-time issues
|
||||
if (dataSize > MAX_DATA_SIZE)
|
||||
if (dataSize > MessageTransaction.MAX_DATA_SIZE)
|
||||
throw new TransformationException("MessageTransaction data size too large");
|
||||
|
||||
byte[] data = new byte[dataSize];
|
||||
byteBuffer.get(data);
|
||||
|
||||
// Still need to make sure there are enough bytes left for remaining fields
|
||||
if (byteBuffer.remaining() < IS_ENCRYPTED_LENGTH + IS_TEXT_LENGTH + FEE_LENGTH + SIGNATURE_LENGTH)
|
||||
throw new TransformationException("Byte data too short for MessageTransaction");
|
||||
|
||||
boolean isEncrypted = byteBuffer.get() != 0;
|
||||
boolean isText = byteBuffer.get() != 0;
|
||||
|
||||
|
@ -37,6 +37,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case PAYMENT:
|
||||
return PaymentTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
@ -68,6 +71,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case PAYMENT:
|
||||
return PaymentTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
@ -99,6 +105,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case PAYMENT:
|
||||
return PaymentTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
@ -130,6 +139,9 @@ public class TransactionTransformer extends Transformer {
|
||||
case PAYMENT:
|
||||
return PaymentTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case CREATE_POLL:
|
||||
return CreatePollTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case ISSUE_ASSET:
|
||||
return IssueAssetTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
|
@ -68,10 +68,16 @@ public class Serialization {
|
||||
}
|
||||
|
||||
public static String deserializeSizedString(ByteBuffer byteBuffer, int maxSize) throws TransformationException {
|
||||
if (byteBuffer.remaining() < Transformer.INT_LENGTH)
|
||||
throw new TransformationException("Byte data too short for serialized string size");
|
||||
|
||||
int size = byteBuffer.getInt();
|
||||
if (size > maxSize || size > byteBuffer.remaining())
|
||||
if (size > maxSize)
|
||||
throw new TransformationException("Serialized string too long");
|
||||
|
||||
if (size > byteBuffer.remaining())
|
||||
throw new TransformationException("Byte data too short for serialized string");
|
||||
|
||||
byte[] bytes = new byte[size];
|
||||
byteBuffer.get(bytes);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user