diff --git a/lib/org/ciyam/at/1.0/at-1.0.jar b/lib/org/ciyam/at/1.0/at-1.0.jar index 1b554f34..669e9887 100644 Binary files a/lib/org/ciyam/at/1.0/at-1.0.jar and b/lib/org/ciyam/at/1.0/at-1.0.jar differ diff --git a/lib/org/ciyam/at/1.0/at-1.0.jar.md5 b/lib/org/ciyam/at/1.0/at-1.0.jar.md5 index c06cf86a..be960be8 100644 --- a/lib/org/ciyam/at/1.0/at-1.0.jar.md5 +++ b/lib/org/ciyam/at/1.0/at-1.0.jar.md5 @@ -1 +1 @@ -1d6f5d634a2c4e570a5a8af260a51653 \ No newline at end of file +ab1560171ae5c6c15b0dfa8e6cccc7f8 \ No newline at end of file diff --git a/lib/org/ciyam/at/1.0/at-1.0.jar.sha1 b/lib/org/ciyam/at/1.0/at-1.0.jar.sha1 index 2f748fd6..29767395 100644 --- a/lib/org/ciyam/at/1.0/at-1.0.jar.sha1 +++ b/lib/org/ciyam/at/1.0/at-1.0.jar.sha1 @@ -1 +1 @@ -c6387380bc5db1f0a98ecbb480b17bd89b564401 \ No newline at end of file +c293c9656f43b432a08053f19ec5aa0de1cd10ea \ No newline at end of file diff --git a/lib/org/ciyam/at/maven-metadata-local.xml b/lib/org/ciyam/at/maven-metadata-local.xml new file mode 100644 index 00000000..513f5312 --- /dev/null +++ b/lib/org/ciyam/at/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + org.ciyam + at + + 1.0 + + 1.0 + + 20181015085522 + + diff --git a/lib/org/ciyam/at/maven-metadata.xml b/lib/org/ciyam/at/maven-metadata.xml index 9b556545..dd714561 100644 --- a/lib/org/ciyam/at/maven-metadata.xml +++ b/lib/org/ciyam/at/maven-metadata.xml @@ -7,6 +7,6 @@ 1.0 - 20181003154752 + 20181015081124 diff --git a/lib/org/ciyam/at/maven-metadata.xml.md5 b/lib/org/ciyam/at/maven-metadata.xml.md5 index de530860..e8f9b7d2 100644 --- a/lib/org/ciyam/at/maven-metadata.xml.md5 +++ b/lib/org/ciyam/at/maven-metadata.xml.md5 @@ -1 +1 @@ -bc81bc1f9b74a4eececd5dd8b29e47d8 \ No newline at end of file +2369bf36c52580a89d5ea71a0f037a82 \ No newline at end of file diff --git a/lib/org/ciyam/at/maven-metadata.xml.sha1 b/lib/org/ciyam/at/maven-metadata.xml.sha1 index 1746aa6b..88816e70 100644 --- a/lib/org/ciyam/at/maven-metadata.xml.sha1 +++ b/lib/org/ciyam/at/maven-metadata.xml.sha1 @@ -1 +1 @@ -feefde4343bda4d6e13159e5c01f8b4f8963a1bc \ No newline at end of file +6bc38899b93ffce2286ae26f7af0b2d8b69db3cf \ No newline at end of file diff --git a/src/data/transaction/ATTransactionData.java b/src/data/transaction/ATTransactionData.java index 43053561..8d9f99de 100644 --- a/src/data/transaction/ATTransactionData.java +++ b/src/data/transaction/ATTransactionData.java @@ -10,22 +10,25 @@ public class ATTransactionData extends TransactionData { private byte[] senderPublicKey; private String recipient; private BigDecimal amount; + private Long assetId; private byte[] message; // Constructors - public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, byte[] message, BigDecimal fee, long timestamp, byte[] reference, - byte[] signature) { + public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, + byte[] reference, byte[] signature) { super(TransactionType.AT, fee, senderPublicKey, timestamp, reference, signature); this.senderPublicKey = senderPublicKey; this.recipient = recipient; this.amount = amount; + this.assetId = assetId; this.message = message; } - public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, byte[] message, BigDecimal fee, long timestamp, byte[] reference) { - this(senderPublicKey, recipient, amount, message, fee, timestamp, reference, null); + public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, + byte[] reference) { + this(senderPublicKey, recipient, amount, assetId, message, fee, timestamp, reference, null); } // Getters/Setters @@ -42,6 +45,10 @@ public class ATTransactionData extends TransactionData { return this.amount; } + public Long getAssetId() { + return this.assetId; + } + public byte[] getMessage() { return this.message; } diff --git a/src/qora/at/AT.java b/src/qora/at/AT.java index 8c1a9b99..292ff62b 100644 --- a/src/qora/at/AT.java +++ b/src/qora/at/AT.java @@ -1,5 +1,7 @@ package qora.at; +import java.nio.ByteBuffer; + import org.ciyam.at.MachineState; import data.at.ATData; @@ -26,20 +28,51 @@ public class AT { public AT(Repository repository, DeployATTransactionData deployATTransactionData) throws DataException { this.repository = repository; - MachineState machineState = new MachineState(deployATTransactionData.getCreationBytes()); - - this.atData = new ATData(deployATTransactionData.getATAddress(), machineState.version, machineState.codeByteBuffer.array(), machineState.isSleeping, - machineState.sleepUntilHeight, machineState.isFinished, machineState.hadFatalError, machineState.isFrozen, machineState.frozenBalance, - deployATTransactionData.getSignature()); - - String atAddress = this.atData.getATAddress(); - + String atAddress = deployATTransactionData.getATAddress(); int height = this.repository.getBlockRepository().getBlockchainHeight(); - byte[] stateData = machineState.toBytes(); - this.atStateData = new ATStateData(atAddress, height, stateData); + byte[] creationBytes = deployATTransactionData.getCreationBytes(); + short version = (short) (creationBytes[0] | (creationBytes[1] << 8)); // Little-endian + + if (version >= 2) { + MachineState machineState = new MachineState(deployATTransactionData.getCreationBytes()); + + this.atData = new ATData(atAddress, machineState.version, machineState.getCodeBytes(), machineState.getIsSleeping(), + machineState.getSleepUntilHeight(), machineState.getIsFinished(), machineState.getHadFatalError(), machineState.getIsFrozen(), + machineState.getFrozenBalance(), deployATTransactionData.getSignature()); + + this.atStateData = new ATStateData(atAddress, height, machineState.toBytes()); + } else { + // Legacy v1 AT in 'dead' state + // Extract code bytes length + ByteBuffer byteBuffer = ByteBuffer.wrap(deployATTransactionData.getCreationBytes()); + + short numCodePages = byteBuffer.get(2 + 2); + + byteBuffer.position(6 * 2 + 8); + int codeLen = 0; + + if (numCodePages * 256 < 257) { + codeLen = (int) (byteBuffer.get() & 0xff); + } else if (numCodePages * 256 < Short.MAX_VALUE + 1) { + codeLen = byteBuffer.getShort() & 0xffff; + } else if (numCodePages * 256 <= Integer.MAX_VALUE) { + codeLen = byteBuffer.getInt(); + } + + // Extract code bytes + byte[] codeBytes = new byte[codeLen]; + byteBuffer.get(codeBytes); + + this.atData = new ATData(deployATTransactionData.getATAddress(), 1, codeBytes, false, null, true, false, false, (Long) null, + deployATTransactionData.getSignature()); + + this.atStateData = new ATStateData(deployATTransactionData.getATAddress(), height, null); + } } + // Processing + public void deploy() throws DataException { this.repository.getATRepository().save(this.atData); this.repository.getATRepository().save(this.atStateData); diff --git a/src/qora/block/Block.java b/src/qora/block/Block.java index 5dc2340f..44fdea7d 100644 --- a/src/qora/block/Block.java +++ b/src/qora/block/Block.java @@ -612,7 +612,7 @@ public class Block { Transaction.ValidationResult validationResult = transaction.isValid(); if (validationResult != Transaction.ValidationResult.OK) { LOGGER.error("Error during transaction validation, tx " + Base58.encode(transaction.getTransactionData().getSignature()) + ": " - + validationResult.value); + + validationResult.name()); return ValidationResult.TRANSACTION_INVALID; } diff --git a/src/qora/transaction/ATTransaction.java b/src/qora/transaction/ATTransaction.java new file mode 100644 index 00000000..e3be08e9 --- /dev/null +++ b/src/qora/transaction/ATTransaction.java @@ -0,0 +1,128 @@ +package qora.transaction; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import data.PaymentData; +import data.transaction.ATTransactionData; +import data.transaction.TransactionData; +import qora.account.Account; +import qora.account.PublicKeyAccount; +import qora.assets.Asset; +import qora.payment.Payment; +import repository.DataException; +import repository.Repository; + +public class ATTransaction extends Transaction { + + // Properties + private ATTransactionData atTransactionData; + + // Other useful constants + public static final int MAX_DATA_SIZE = 256; + + // Constructors + + public ATTransaction(Repository repository, TransactionData transactionData) { + super(repository, transactionData); + + this.atTransactionData = (ATTransactionData) this.transactionData; + } + + // More information + + @Override + public List getRecipientAccounts() throws DataException { + return Collections.singletonList(new Account(this.repository, atTransactionData.getRecipient())); + } + + @Override + public boolean isInvolved(Account account) throws DataException { + String address = account.getAddress(); + + if (address.equals(this.getSender().getAddress())) + return true; + + if (address.equals(atTransactionData.getRecipient())) + return true; + + return false; + } + + @Override + public BigDecimal getAmount(Account account) throws DataException { + String address = account.getAddress(); + BigDecimal amount = BigDecimal.ZERO.setScale(8); + String senderAddress = this.getSender().getAddress(); + + if (address.equals(senderAddress)) { + amount = amount.subtract(this.atTransactionData.getFee()); + + if (atTransactionData.getAmount() != null && atTransactionData.getAssetId() == Asset.QORA) + amount = amount.subtract(atTransactionData.getAmount()); + } + + if (address.equals(atTransactionData.getRecipient()) && atTransactionData.getAmount() != null) + amount = amount.add(atTransactionData.getAmount()); + + return amount; + } + + // Navigation + + public Account getSender() throws DataException { + return new PublicKeyAccount(this.repository, this.atTransactionData.getSenderPublicKey()); + } + + // Processing + + private PaymentData getPaymentData() { + if (atTransactionData.getAmount() == null) + return null; + + return new PaymentData(atTransactionData.getRecipient(), atTransactionData.getAssetId(), atTransactionData.getAmount()); + } + + @Override + public ValidationResult isValid() throws DataException { + // Check reference is correct + Account sender = getSender(); + if (!Arrays.equals(sender.getLastReference(), atTransactionData.getReference())) + return ValidationResult.INVALID_REFERENCE; + + if (this.atTransactionData.getMessage().length > MAX_DATA_SIZE) + return ValidationResult.INVALID_DATA_LENGTH; + + // If we have no payment then we're done + if (this.atTransactionData.getAmount() == null) + return ValidationResult.OK; + + // Wrap and delegate final payment checks to Payment class + return new Payment(this.repository).isValid(atTransactionData.getSenderPublicKey(), getPaymentData(), atTransactionData.getFee()); + } + + @Override + public void process() throws DataException { + // Save this transaction itself + this.repository.getTransactionRepository().save(this.transactionData); + + if (this.atTransactionData.getAmount() != null) + // Wrap and delegate payment processing to Payment class. Only update recipient's last reference if transferring QORA. + new Payment(this.repository).process(atTransactionData.getSenderPublicKey(), getPaymentData(), atTransactionData.getFee(), + atTransactionData.getSignature(), false); + } + + @Override + public void orphan() throws DataException { + // Delete this transaction + this.repository.getTransactionRepository().delete(this.transactionData); + + if (this.atTransactionData.getAmount() != null) + // Wrap and delegate payment processing to Payment class. Only revert recipient's last reference if transferring QORA. + new Payment(this.repository).orphan(atTransactionData.getSenderPublicKey(), getPaymentData(), atTransactionData.getFee(), + atTransactionData.getSignature(), atTransactionData.getReference(), false); + } + +} diff --git a/src/qora/transaction/DeployATTransaction.java b/src/qora/transaction/DeployATTransaction.java index 45d77600..699b0654 100644 --- a/src/qora/transaction/DeployATTransaction.java +++ b/src/qora/transaction/DeployATTransaction.java @@ -75,6 +75,13 @@ public class DeployATTransaction extends Transaction { return amount; } + /** Returns AT version from the header bytes */ + private short getVersion() { + byte[] creationBytes = deployATTransactionData.getCreationBytes(); + short version = (short) (creationBytes[0] | (creationBytes[1] << 8)); // Little-endian + return version; + } + /** Make sure deployATTransactionData has an ATAddress */ private void ensureATAddress() throws DataException { if (this.deployATTransactionData.getATAddress() != null) @@ -82,7 +89,7 @@ public class DeployATTransaction extends Transaction { int blockHeight = this.getHeight(); if (blockHeight == 0) - blockHeight = this.repository.getBlockRepository().getBlockchainHeight(); + blockHeight = this.repository.getBlockRepository().getBlockchainHeight() + 1; try { byte[] name = this.deployATTransactionData.getName().getBytes("UTF-8"); @@ -163,11 +170,8 @@ public class DeployATTransaction extends Transaction { if (creator.getConfirmedBalance(Asset.QORA).compareTo(minimumBalance) < 0) return ValidationResult.NO_BALANCE; - // Check creation bytes are valid (for v3+) - byte[] creationBytes = deployATTransactionData.getCreationBytes(); - short version = (short) (creationBytes[0] | (creationBytes[1] << 8)); // Little-endian - - if (version >= 3) { + // Check creation bytes are valid (for v2+) + if (this.getVersion() >= 2) { // Do actual validation } else { // Skip validation for old, dead ATs @@ -194,6 +198,14 @@ public class DeployATTransaction extends Transaction { // Update creator's reference creator.setLastReference(deployATTransactionData.getSignature()); + + // Update AT's reference, which also creates AT account + Account atAccount = this.getATAccount(); + atAccount.setLastReference(deployATTransactionData.getSignature()); + + // Update AT's balance + atAccount.setConfirmedBalance(Asset.QORA, deployATTransactionData.getAmount()); + } @Override @@ -212,6 +224,9 @@ public class DeployATTransaction extends Transaction { // Update creator's reference creator.setLastReference(deployATTransactionData.getReference()); + + // Delete AT's account + this.repository.getAccountRepository().delete(this.deployATTransactionData.getATAddress()); } } diff --git a/src/qora/transaction/Transaction.java b/src/qora/transaction/Transaction.java index aaba8836..f532e3bf 100644 --- a/src/qora/transaction/Transaction.java +++ b/src/qora/transaction/Transaction.java @@ -193,11 +193,14 @@ public abstract class Transaction { case MULTIPAYMENT: return new MultiPaymentTransaction(repository, transactionData); + case DEPLOY_AT: + return new DeployATTransaction(repository, transactionData); + case MESSAGE: return new MessageTransaction(repository, transactionData); - case DEPLOY_AT: - return new DeployATTransaction(repository, transactionData); + case AT: + return new ATTransaction(repository, transactionData); default: throw new IllegalStateException("Unsupported transaction type [" + transactionData.getType().value + "] during fetch from repository"); diff --git a/src/repository/AccountRepository.java b/src/repository/AccountRepository.java index d740fe80..5983ebfb 100644 --- a/src/repository/AccountRepository.java +++ b/src/repository/AccountRepository.java @@ -11,6 +11,8 @@ public interface AccountRepository { public void save(AccountData accountData) throws DataException; + public void delete(String address) throws DataException; + // Account balances public AccountBalanceData getBalance(String address, long assetId) throws DataException; diff --git a/src/repository/hsqldb/HSQLDBATRepository.java b/src/repository/hsqldb/HSQLDBATRepository.java index 5c2cc88d..4cb0cd23 100644 --- a/src/repository/hsqldb/HSQLDBATRepository.java +++ b/src/repository/hsqldb/HSQLDBATRepository.java @@ -69,7 +69,7 @@ public class HSQLDBATRepository implements ATRepository { @Override public void delete(String atAddress) throws DataException { try { - this.repository.delete("ATs", "atAddress = ?", atAddress); + this.repository.delete("ATs", "AT_address = ?", atAddress); // AT States also deleted via ON DELETE CASCADE } catch (SQLException e) { throw new DataException("Unable to delete AT from repository", e); diff --git a/src/repository/hsqldb/HSQLDBAccountRepository.java b/src/repository/hsqldb/HSQLDBAccountRepository.java index 1e2c669e..d56604b3 100644 --- a/src/repository/hsqldb/HSQLDBAccountRepository.java +++ b/src/repository/hsqldb/HSQLDBAccountRepository.java @@ -17,6 +17,8 @@ public class HSQLDBAccountRepository implements AccountRepository { this.repository = repository; } + // General account + @Override public AccountData getAccount(String address) throws DataException { try (ResultSet resultSet = this.repository.checkedExecute("SELECT reference FROM Accounts WHERE account = ?", address)) { @@ -41,6 +43,19 @@ public class HSQLDBAccountRepository implements AccountRepository { } } + @Override + public void delete(String address) throws DataException { + // NOTE: Account balances are deleted automatically by the database thanks to "ON DELETE CASCADE" in AccountBalances' FOREIGN KEY + // definition. + try { + this.repository.delete("Accounts", "account = ?", address); + } catch (SQLException e) { + throw new DataException("Unable to delete account from repository", e); + } + } + + // Account balances + @Override public AccountBalanceData getBalance(String address, long assetId) throws DataException { try (ResultSet resultSet = this.repository.checkedExecute("SELECT balance FROM AccountBalances WHERE account = ? and asset_id = ?", address, assetId)) { diff --git a/src/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/repository/hsqldb/HSQLDBDatabaseUpdates.java index f3f1dba7..e8efb45a 100644 --- a/src/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -99,6 +99,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TYPE ATType AS VARCHAR(200) COLLATE SQL_TEXT_UCC_NO_PAD"); stmt.execute("CREATE TYPE ATCode AS BLOB(64K)"); // 16bit * 1 stmt.execute("CREATE TYPE ATState AS BLOB(1M)"); // 16bit * 8 + 16bit * 4 + 16bit * 4 + stmt.execute("CREATE TYPE ATStateHash as VARBINARY(32)"); stmt.execute("CREATE TYPE ATMessage AS VARBINARY(256)"); break; @@ -302,7 +303,7 @@ public class HSQLDBDatabaseUpdates { // Accounts stmt.execute("CREATE TABLE Accounts (account QoraAddress, reference Signature, PRIMARY KEY (account))"); stmt.execute("CREATE TABLE AccountBalances (account QoraAddress, asset_id AssetID, balance QoraAmount NOT NULL, " - + "PRIMARY KEY (account, asset_id))"); + + "PRIMARY KEY (account, asset_id), FOREIGN KEY (account) REFERENCES Accounts (account) ON DELETE CASCADE)"); break; case 23: @@ -358,11 +359,12 @@ public class HSQLDBDatabaseUpdates { // For finding executable ATs stmt.execute("CREATE INDEX ATIndex on ATs (is_finished, AT_address)"); // AT state on a per-block basis - stmt.execute("CREATE TABLE ATStates (AT_address QoraAddress, height INTEGER NOT NULL, state_data ATState, " - + "PRIMARY KEY (AT_address, height), FOREIGN KEY (AT_address) REFERENCES ATs (AT_address) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE ATStates (AT_address QoraAddress, height INTEGER NOT NULL, state_data ATState, state_hash ATStateHash NOT NULL, fees QoraAmount NOT NULL, " + + "PRIMARY KEY (AT_address, height), FOREIGN KEY (AT_address) REFERENCES ATs (AT_address) ON DELETE CASCADE)"); // Generated AT Transactions stmt.execute( - "CREATE TABLE ATTransactions (signature Signature, sender QoraPublicKey NOT NULL, recipient QoraAddress, amount QoraAmount NOT NULL, message ATMessage, " + "CREATE TABLE ATTransactions (signature Signature, sender QoraPublicKey NOT NULL, recipient QoraAddress, amount QoraAmount, asset_id AssetID, message ATMessage, " + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); break; diff --git a/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java b/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java new file mode 100644 index 00000000..279c540a --- /dev/null +++ b/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java @@ -0,0 +1,63 @@ +package repository.hsqldb.transaction; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; + +import data.transaction.ATTransactionData; +import data.transaction.TransactionData; +import repository.DataException; +import repository.hsqldb.HSQLDBRepository; +import repository.hsqldb.HSQLDBSaver; + +public class HSQLDBATTransactionRepository extends HSQLDBTransactionRepository { + + public HSQLDBATTransactionRepository(HSQLDBRepository repository) { + this.repository = repository; + } + + TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT sender, recipient, amount, asset_id, message FROM ATTransactions WHERE signature = ?", + signature)) { + if (resultSet == null) + return null; + + byte[] senderPublicKey = resultSet.getBytes(1); + String recipient = resultSet.getString(2); + + BigDecimal amount = resultSet.getBigDecimal(3); + if (resultSet.wasNull()) + amount = null; + + Long assetId = resultSet.getLong(4); + if (resultSet.wasNull()) + assetId = null; + + byte[] message = resultSet.getBytes(5); + if (resultSet.wasNull()) + message = null; + + return new ATTransactionData(senderPublicKey, recipient, amount, assetId, message, fee, timestamp, reference, signature); + } catch (SQLException e) { + throw new DataException("Unable to fetch AT transaction from repository", e); + } + } + + @Override + public void save(TransactionData transactionData) throws DataException { + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + HSQLDBSaver saveHelper = new HSQLDBSaver("ATTransactions"); + + saveHelper.bind("signature", atTransactionData.getSignature()).bind("sender", atTransactionData.getSenderPublicKey()) + .bind("recipient", atTransactionData.getRecipient()).bind("amount", atTransactionData.getAmount()) + .bind("asset_id", atTransactionData.getAssetId()).bind("message", atTransactionData.getMessage()); + + try { + saveHelper.execute(this.repository); + } catch (SQLException e) { + throw new DataException("Unable to save AT transaction into repository", e); + } + } + +} diff --git a/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index 316ee6a7..9a2ade4d 100644 --- a/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -37,6 +37,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { private HSQLDBMultiPaymentTransactionRepository multiPaymentTransactionRepository; private HSQLDBDeployATTransactionRepository deployATTransactionRepository; private HSQLDBMessageTransactionRepository messageTransactionRepository; + private HSQLDBATTransactionRepository atTransactionRepository; public HSQLDBTransactionRepository(HSQLDBRepository repository) { this.repository = repository; @@ -57,6 +58,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { this.multiPaymentTransactionRepository = new HSQLDBMultiPaymentTransactionRepository(repository); this.deployATTransactionRepository = new HSQLDBDeployATTransactionRepository(repository); this.messageTransactionRepository = new HSQLDBMessageTransactionRepository(repository); + this.atTransactionRepository = new HSQLDBATTransactionRepository(repository); } protected HSQLDBTransactionRepository() { @@ -154,8 +156,11 @@ public class HSQLDBTransactionRepository implements TransactionRepository { case MESSAGE: return this.messageTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee); + case AT: + return this.atTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee); + default: - throw new DataException("Unsupported transaction type [" + type.value + "] during fetch from HSQLDB repository"); + throw new DataException("Unsupported transaction type [" + type.name() + "] during fetch from HSQLDB repository"); } } @@ -317,8 +322,12 @@ public class HSQLDBTransactionRepository implements TransactionRepository { this.messageTransactionRepository.save(transactionData); break; + case AT: + this.atTransactionRepository.save(transactionData); + break; + default: - throw new DataException("Unsupported transaction type [" + transactionData.getType().value + "] during save into HSQLDB repository"); + throw new DataException("Unsupported transaction type [" + transactionData.getType().name() + "] during save into HSQLDB repository"); } } diff --git a/src/transform/transaction/DeployATTransactionTransformer.java b/src/transform/transaction/DeployATTransactionTransformer.java index 0699084f..12d78906 100644 --- a/src/transform/transaction/DeployATTransactionTransformer.java +++ b/src/transform/transaction/DeployATTransactionTransformer.java @@ -97,7 +97,9 @@ public class DeployATTransactionTransformer extends TransactionTransformer { Serialization.serializeSizedString(bytes, deployATTransactionData.getTags()); - bytes.write(deployATTransactionData.getCreationBytes()); + byte[] creationBytes = deployATTransactionData.getCreationBytes(); + bytes.write(Ints.toByteArray(creationBytes.length)); + bytes.write(creationBytes); Serialization.serializeBigDecimal(bytes, deployATTransactionData.getAmount()); @@ -146,15 +148,14 @@ public class DeployATTransactionTransformer extends TransactionTransformer { // Omitted: Serialization.serializeSizedString(bytes, deployATTransactionData.getTags()); - bytes.write(deployATTransactionData.getCreationBytes()); + byte[] creationBytes = deployATTransactionData.getCreationBytes(); + bytes.write(Ints.toByteArray(creationBytes.length)); + bytes.write(creationBytes); Serialization.serializeBigDecimal(bytes, deployATTransactionData.getAmount()); Serialization.serializeBigDecimal(bytes, deployATTransactionData.getFee()); - if (deployATTransactionData.getSignature() != null) - bytes.write(deployATTransactionData.getSignature()); - return bytes.toByteArray(); } catch (IOException | ClassCastException e) { throw new TransformationException(e); diff --git a/src/v1feeder.java b/src/v1feeder.java index 42d69f7f..a2c13a30 100644 --- a/src/v1feeder.java +++ b/src/v1feeder.java @@ -221,8 +221,8 @@ public class v1feeder extends Thread { ValidationResult result = block.isValid(); if (result != ValidationResult.OK) { - LOGGER.error("Invalid block, validation result code: " + result.value); - throw new RuntimeException("Invalid block, validation result code: " + result.value); + LOGGER.error("Invalid block, validation result: " + result.name()); + throw new RuntimeException("Invalid block, validation result: " + result.name()); } block.process();