From 46eee3cbcefbeea6b1c1d0c5bdfbaa7d84a3f9ca Mon Sep 17 00:00:00 2001 From: catbref Date: Mon, 15 Oct 2018 15:12:41 +0100 Subject: [PATCH 1/2] More work on CIYAM AT support. ATs can create AT-Transactions which contain payments (of any asset) and/or messages. Legacy Qora1 DeployATTransactions create AT records in the repository but set to "finished" so that they never execute. More repository support for ATs. In HSQLDB, create a new TYPE called ATStateHash which is used to verify the same AT outcome on a per-block basis. Added Accounts.account as a foreign key to AccountBalances with ON DELETE CASCADE. ATStates now include state_hash and fees on a per-block basis. ATTransactions now include asset_id. When transforming DeployATTransactions, don't include any signature when collating bytes for signing! --- lib/org/ciyam/at/1.0/at-1.0.jar | Bin 131739 -> 133773 bytes lib/org/ciyam/at/1.0/at-1.0.jar.md5 | 2 +- lib/org/ciyam/at/1.0/at-1.0.jar.sha1 | 2 +- lib/org/ciyam/at/maven-metadata-local.xml | 12 ++ lib/org/ciyam/at/maven-metadata.xml | 2 +- lib/org/ciyam/at/maven-metadata.xml.md5 | 2 +- lib/org/ciyam/at/maven-metadata.xml.sha1 | 2 +- src/data/transaction/ATTransactionData.java | 15 +- src/qora/at/AT.java | 53 ++++++-- src/qora/block/Block.java | 2 +- src/qora/transaction/ATTransaction.java | 128 ++++++++++++++++++ src/qora/transaction/DeployATTransaction.java | 27 +++- src/qora/transaction/Transaction.java | 7 +- src/repository/AccountRepository.java | 2 + src/repository/hsqldb/HSQLDBATRepository.java | 2 +- .../hsqldb/HSQLDBAccountRepository.java | 15 ++ .../hsqldb/HSQLDBDatabaseUpdates.java | 10 +- .../HSQLDBATTransactionRepository.java | 63 +++++++++ .../HSQLDBTransactionRepository.java | 13 +- .../DeployATTransactionTransformer.java | 11 +- src/v1feeder.java | 4 +- 21 files changed, 332 insertions(+), 42 deletions(-) create mode 100644 lib/org/ciyam/at/maven-metadata-local.xml create mode 100644 src/qora/transaction/ATTransaction.java create mode 100644 src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java 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 1b554f3425f2dbc909f0d2ae720d7164fd7ff5f3..669e9887e2c1f44eac8a8a9f43e649db030b9933 100644 GIT binary patch literal 133773 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

4_vx$NZh!Yq80UY!#ogGMv1wl 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 SYEOWZ1p3>_Oaiyi;QkLqMPPOS 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(); From 2c51a0362b98fc81da70ba2918ef6798e9c89441 Mon Sep 17 00:00:00 2001 From: catbref Date: Fri, 26 Oct 2018 17:47:47 +0100 Subject: [PATCH 2/2] Finally syncs with qora1 chain! ATData no longer needs deploySignature as a link back to DeployATTransaction, but does need creator and creation [timestamp]. "creation" is critical for ordering ATs when creating/validating blocks. Similar changes to ATStateData, adding creation, stateHash (for quicker comparison with blocks received over the network), and fees incurred by running AT on that block. Also added more explicit constructors for different scenarios. BlockData upgraded from simplistic "atBytes" to use ATStateData (above) which has details on ATs run for that block, fees incurred, and a hash of the AT's state. atCount added to keep track of how many ATs ran. ATTransactions essentially reuse the GenesisAccount's publickey as creator/sender as they're brought into existence by the Qora code rather than an end user. ATTransactionData updated to reflect this and the AT's address used as a "sender" field. Account tidied up with respect to CIYAM ATs and setConfirmedBalance ensures there is a corresponding record in Accounts (DB table). Account, and subclasses, don't need "throws DataException" on constructor any more. Fixed bug in Asset Order matching where the matching engine would give up after first potential match instead of trying others. Lots more work on CIYAM AT, albeit mainly blind importing of old v1 ATs from static JSON file as they're all dead and new v2 implementation is not backwards compatible. More work on Blocks, mostly AT stuff, but also fork-based corruption prevention using fix from Qora v1. Payment-related transactions (multipayment, etc.) always expect/use non-null (albeit maybe empty) list of PaymentData when validating, processing or orphaning. Mainly a change in HSQLDBTransactionRepository.getPayments() Payment.isValid(byte[], PaymentData, BigDecimal, boolean isZeroAmountValid) didn't pass on isZeroAmountValid to called method - whoops! Lots of work on ATTransactions themselves. MessageTransactions incorrectly assumed the optional payment was always in Qora. Now fixed to use the transaction's provided assetId. Mass of fixes/additions to HSQLDBATRepository, especially fixing incorrect reference to Assets DB table! In HSQLDBDatabaseUpdates, bump QoraAmount type from DECIMAL(19,8) to DECIMAL(27,8) to allow for huge asset quantities. You WILL have to rebuild your database! --- src/data/at/ATData.java | 28 +- src/data/at/ATStateData.java | 47 ++- src/data/block/BlockData.java | 68 +++-- src/data/block/BlockTransactionData.java | 6 +- src/data/transaction/ATTransactionData.java | 17 +- src/qora/account/Account.java | 25 +- src/qora/account/GenesisAccount.java | 3 +- src/qora/account/PublicKeyAccount.java | 3 +- src/qora/assets/Order.java | 8 +- src/qora/at/AT.java | 23 +- src/qora/block/Block.java | 267 ++++++++++++++---- src/qora/block/GenesisBlock.java | 2 +- src/qora/payment/Payment.java | 99 ++++--- src/qora/transaction/ATTransaction.java | 119 +++++--- .../transaction/ArbitraryTransaction.java | 4 +- src/qora/transaction/DeployATTransaction.java | 1 - src/qora/transaction/GenesisTransaction.java | 15 +- src/qora/transaction/MessageTransaction.java | 2 +- src/repository/ATRepository.java | 8 + src/repository/AccountRepository.java | 2 + src/repository/hsqldb/HSQLDBATRepository.java | 98 +++++-- .../hsqldb/HSQLDBAccountRepository.java | 15 + .../hsqldb/HSQLDBBlockRepository.java | 13 +- .../hsqldb/HSQLDBDatabaseUpdates.java | 25 +- .../HSQLDBATTransactionRepository.java | 10 +- .../HSQLDBTransactionRepository.java | 15 +- src/test/ATTests.java | 14 +- src/test/NavigationTests.java | 2 +- src/test/SignatureTests.java | 6 +- src/test/TransactionTests.java | 34 +-- src/transform/Transformer.java | 3 + src/transform/block/BlockTransformer.java | 173 +++++++++--- .../transaction/ATTransactionTransformer.java | 92 ++++++ src/utils/Pair.java | 18 ++ src/utils/Triple.java | 42 +++ src/v1feeder.java | 133 ++++++++- 36 files changed, 1075 insertions(+), 365 deletions(-) create mode 100644 src/transform/transaction/ATTransactionTransformer.java create mode 100644 src/utils/Triple.java diff --git a/src/data/at/ATData.java b/src/data/at/ATData.java index bf8272e6..41278c51 100644 --- a/src/data/at/ATData.java +++ b/src/data/at/ATData.java @@ -6,6 +6,8 @@ public class ATData { // Properties private String ATAddress; + private String creator; + private long creation; private int version; private byte[] codeBytes; private boolean isSleeping; @@ -14,13 +16,14 @@ public class ATData { private boolean hadFatalError; private boolean isFrozen; private BigDecimal frozenBalance; - private byte[] deploySignature; // Constructors - public ATData(String ATAddress, int version, byte[] codeBytes, boolean isSleeping, Integer sleepUntilHeight, boolean isFinished, boolean hadFatalError, - boolean isFrozen, BigDecimal frozenBalance, byte[] deploySignature) { + public ATData(String ATAddress, String creator, long creation, int version, byte[] codeBytes, boolean isSleeping, Integer sleepUntilHeight, + boolean isFinished, boolean hadFatalError, boolean isFrozen, BigDecimal frozenBalance) { this.ATAddress = ATAddress; + this.creator = creator; + this.creation = creation; this.version = version; this.codeBytes = codeBytes; this.isSleeping = isSleeping; @@ -29,12 +32,11 @@ public class ATData { this.hadFatalError = hadFatalError; this.isFrozen = isFrozen; this.frozenBalance = frozenBalance; - this.deploySignature = deploySignature; } - public ATData(String ATAddress, int version, byte[] codeBytes, boolean isSleeping, Integer sleepUntilHeight, boolean isFinished, boolean hadFatalError, - boolean isFrozen, Long frozenBalance, byte[] deploySignature) { - this(ATAddress, version, codeBytes, isSleeping, sleepUntilHeight, isFinished, hadFatalError, isFrozen, (BigDecimal) null, deploySignature); + public ATData(String ATAddress, String creator, long creation, int version, byte[] codeBytes, boolean isSleeping, Integer sleepUntilHeight, + boolean isFinished, boolean hadFatalError, boolean isFrozen, Long frozenBalance) { + this(ATAddress, creator, creation, version, codeBytes, isSleeping, sleepUntilHeight, isFinished, hadFatalError, isFrozen, (BigDecimal) null); // Convert Long frozenBalance to BigDecimal if (frozenBalance != null) @@ -47,6 +49,14 @@ public class ATData { return this.ATAddress; } + public String getCreator() { + return this.creator; + } + + public long getCreation() { + return this.creation; + } + public int getVersion() { return this.version; } @@ -103,8 +113,4 @@ public class ATData { this.frozenBalance = frozenBalance; } - public byte[] getDeploySignature() { - return this.deploySignature; - } - } diff --git a/src/data/at/ATStateData.java b/src/data/at/ATStateData.java index 192c8095..7d0fc6f4 100644 --- a/src/data/at/ATStateData.java +++ b/src/data/at/ATStateData.java @@ -1,18 +1,42 @@ package data.at; +import java.math.BigDecimal; + public class ATStateData { // Properties private String ATAddress; - private int height; + private Integer height; + private Long creation; private byte[] stateData; + private byte[] stateHash; + private BigDecimal fees; // Constructors - public ATStateData(String ATAddress, int height, byte[] stateData) { + /** Create new ATStateData */ + public ATStateData(String ATAddress, Integer height, Long creation, byte[] stateData, byte[] stateHash, BigDecimal fees) { this.ATAddress = ATAddress; this.height = height; + this.creation = creation; this.stateData = stateData; + this.stateHash = stateHash; + this.fees = fees; + } + + /** For recreating per-block ATStateData from repository where not all info is needed */ + public ATStateData(String ATAddress, int height, byte[] stateHash, BigDecimal fees) { + this(ATAddress, height, null, null, stateHash, fees); + } + + /** For creating ATStateData from serialized bytes when we don't have all the info */ + public ATStateData(String ATAddress, byte[] stateHash) { + this(ATAddress, null, null, null, stateHash, null); + } + + /** For creating ATStateData from serialized bytes when we don't have all the info */ + public ATStateData(String ATAddress, byte[] stateHash, BigDecimal fees) { + this(ATAddress, null, null, null, stateHash, fees); } // Getters / setters @@ -21,12 +45,29 @@ public class ATStateData { return this.ATAddress; } - public int getHeight() { + public Integer getHeight() { return this.height; } + // Likely to be used when block received over network is attached to blockchain + public void setHeight(Integer height) { + this.height = height; + } + + public Long getCreation() { + return this.creation; + } + public byte[] getStateData() { return this.stateData; } + public byte[] getStateHash() { + return this.stateHash; + } + + public BigDecimal getFees() { + return this.fees; + } + } diff --git a/src/data/block/BlockData.java b/src/data/block/BlockData.java index 8c49b71b..838b347e 100644 --- a/src/data/block/BlockData.java +++ b/src/data/block/BlockData.java @@ -12,16 +12,16 @@ public class BlockData { private int transactionCount; private BigDecimal totalFees; private byte[] transactionsSignature; - private int height; + private Integer height; private long timestamp; private BigDecimal generatingBalance; private byte[] generatorPublicKey; private byte[] generatorSignature; - private byte[] atBytes; + private int atCount; private BigDecimal atFees; - public BlockData(int version, byte[] reference, int transactionCount, BigDecimal totalFees, byte[] transactionsSignature, int height, long timestamp, - BigDecimal generatingBalance, byte[] generatorPublicKey, byte[] generatorSignature, byte[] atBytes, BigDecimal atFees) { + public BlockData(int version, byte[] reference, int transactionCount, BigDecimal totalFees, byte[] transactionsSignature, Integer height, long timestamp, + BigDecimal generatingBalance, byte[] generatorPublicKey, byte[] generatorSignature, int atCount, BigDecimal atFees) { this.version = version; this.reference = reference; this.transactionCount = transactionCount; @@ -32,7 +32,7 @@ public class BlockData { this.generatingBalance = generatingBalance; this.generatorPublicKey = generatorPublicKey; this.generatorSignature = generatorSignature; - this.atBytes = atBytes; + this.atCount = atCount; this.atFees = atFees; if (this.generatorSignature != null && this.transactionsSignature != null) @@ -41,6 +41,26 @@ public class BlockData { this.signature = null; } + public byte[] getSignature() { + return this.signature; + } + + public void setSignature(byte[] signature) { + this.signature = signature; + } + + public int getVersion() { + return this.version; + } + + public byte[] getReference() { + return this.reference; + } + + public void setReference(byte[] reference) { + this.reference = reference; + } + public int getTransactionCount() { return this.transactionCount; } @@ -65,31 +85,11 @@ public class BlockData { this.transactionsSignature = transactionsSignature; } - public byte[] getSignature() { - return this.signature; - } - - public void setSignature(byte[] signature) { - this.signature = signature; - } - - public int getVersion() { - return this.version; - } - - public byte[] getReference() { - return this.reference; - } - - public void setReference(byte[] reference) { - this.reference = reference; - } - - public int getHeight() { + public Integer getHeight() { return this.height; } - public void setHeight(int height) { + public void setHeight(Integer height) { this.height = height; } @@ -113,12 +113,20 @@ public class BlockData { this.generatorSignature = generatorSignature; } - public byte[] getAtBytes() { - return this.atBytes; + public int getATCount() { + return this.atCount; } - public BigDecimal getAtFees() { + public void setATCount(int atCount) { + this.atCount = atCount; + } + + public BigDecimal getATFees() { return this.atFees; } + public void setATFees(BigDecimal atFees) { + this.atFees = atFees; + } + } diff --git a/src/data/block/BlockTransactionData.java b/src/data/block/BlockTransactionData.java index fb62079a..fe0410f3 100644 --- a/src/data/block/BlockTransactionData.java +++ b/src/data/block/BlockTransactionData.java @@ -3,9 +3,9 @@ package data.block; public class BlockTransactionData { // Properties - protected byte[] blockSignature; - protected int sequence; - protected byte[] transactionSignature; + private byte[] blockSignature; + private int sequence; + private byte[] transactionSignature; // Constructors diff --git a/src/data/transaction/ATTransactionData.java b/src/data/transaction/ATTransactionData.java index 8d9f99de..e81dc099 100644 --- a/src/data/transaction/ATTransactionData.java +++ b/src/data/transaction/ATTransactionData.java @@ -2,12 +2,13 @@ package data.transaction; import java.math.BigDecimal; +import qora.account.GenesisAccount; import qora.transaction.Transaction.TransactionType; public class ATTransactionData extends TransactionData { // Properties - private byte[] senderPublicKey; + private String atAddress; private String recipient; private BigDecimal amount; private Long assetId; @@ -15,26 +16,26 @@ public class ATTransactionData extends TransactionData { // Constructors - public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, + public ATTransactionData(String atAddress, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - super(TransactionType.AT, fee, senderPublicKey, timestamp, reference, signature); + super(TransactionType.AT, fee, GenesisAccount.PUBLIC_KEY, timestamp, reference, signature); - this.senderPublicKey = senderPublicKey; + this.atAddress = atAddress; this.recipient = recipient; this.amount = amount; this.assetId = assetId; this.message = message; } - public ATTransactionData(byte[] senderPublicKey, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, + public ATTransactionData(String atAddress, String recipient, BigDecimal amount, Long assetId, byte[] message, BigDecimal fee, long timestamp, byte[] reference) { - this(senderPublicKey, recipient, amount, assetId, message, fee, timestamp, reference, null); + this(atAddress, recipient, amount, assetId, message, fee, timestamp, reference, null); } // Getters/Setters - public byte[] getSenderPublicKey() { - return this.senderPublicKey; + public String getATAddress() { + return this.atAddress; } public String getRecipient() { diff --git a/src/qora/account/Account.java b/src/qora/account/Account.java index bbf03dfd..c7a14425 100644 --- a/src/qora/account/Account.java +++ b/src/qora/account/Account.java @@ -28,7 +28,7 @@ public class Account { protected Account() { } - public Account(Repository repository, String address) throws DataException { + public Account(Repository repository, String address) { this.repository = repository; this.accountData = new AccountData(address); } @@ -55,6 +55,7 @@ public class Account { for (int i = 1; i < BlockChain.BLOCK_RETARGET_INTERVAL && blockData != null && blockData.getHeight() > 1; ++i) { Block block = new Block(this.repository, blockData); + // CIYAM AT transactions should be fetched from repository so no special handling needed here for (Transaction transaction : block.getTransactions()) { if (transaction.isInvolved(this)) { final BigDecimal amount = transaction.getAmount(this); @@ -65,19 +66,10 @@ public class Account { } } - // TODO - CIYAM AT support needed - /* - * LinkedHashMap, AT_Transaction> atTxs = db.getATTransactionMap().getATTransactions(block.getHeight(db)); - * Iterator 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(); } // Do not go below 0 - // XXX: How would this even be possible? balance = balance.max(BigDecimal.ZERO); return balance; @@ -102,19 +94,11 @@ public class Account { for (int i = 1; i < confirmations && blockData != null && blockData.getHeight() > 1; ++i) { Block block = new Block(this.repository, blockData); + // CIYAM AT transactions should be fetched from repository so no special handling needed here 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, AT_Transaction> atTxs = - * db.getATTransactionMap().getATTransactions(block.getHeight(db)); Iterator 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(); } @@ -131,6 +115,9 @@ public class Account { } public void setConfirmedBalance(long assetId, BigDecimal balance) throws DataException { + // Can't have a balance without an account - make sure it exists! + this.repository.getAccountRepository().create(this.accountData.getAddress()); + AccountBalanceData accountBalanceData = new AccountBalanceData(this.accountData.getAddress(), assetId, balance); this.repository.getAccountRepository().save(accountBalanceData); diff --git a/src/qora/account/GenesisAccount.java b/src/qora/account/GenesisAccount.java index a989ec4a..34b85b60 100644 --- a/src/qora/account/GenesisAccount.java +++ b/src/qora/account/GenesisAccount.java @@ -1,13 +1,12 @@ package qora.account; -import repository.DataException; import repository.Repository; public final class GenesisAccount extends PublicKeyAccount { public static final byte[] PUBLIC_KEY = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1 }; - public GenesisAccount(Repository repository) throws DataException { + public GenesisAccount(Repository repository) { super(repository, PUBLIC_KEY); } diff --git a/src/qora/account/PublicKeyAccount.java b/src/qora/account/PublicKeyAccount.java index 2762cd6f..1f28e39b 100644 --- a/src/qora/account/PublicKeyAccount.java +++ b/src/qora/account/PublicKeyAccount.java @@ -2,14 +2,13 @@ package qora.account; import qora.crypto.Crypto; import qora.crypto.Ed25519; -import repository.DataException; import repository.Repository; public class PublicKeyAccount extends Account { protected byte[] publicKey; - public PublicKeyAccount(Repository repository, byte[] publicKey) throws DataException { + public PublicKeyAccount(Repository repository, byte[] publicKey) { super(repository, Crypto.toAddress(publicKey)); this.publicKey = publicKey; diff --git a/src/qora/assets/Order.java b/src/qora/assets/Order.java index 56b15cea..e164b53c 100644 --- a/src/qora/assets/Order.java +++ b/src/qora/assets/Order.java @@ -169,9 +169,9 @@ public class Order { BigDecimal matchedAmount = ourAmountLeft.min(theirAmountLeft); LOGGER.trace("matchedAmount: " + matchedAmount.toPlainString() + " " + wantAssetData.getName()); - // If we can't buy anything then we're done + // If we can't buy anything then try another order if (matchedAmount.compareTo(BigDecimal.ZERO) <= 0) - break; + continue; // Calculate amount granularity based on both assets' divisibility BigDecimal increment = this.calculateAmountGranularity(haveAssetData, wantAssetData, theirOrderData); @@ -179,9 +179,9 @@ public class Order { matchedAmount = matchedAmount.subtract(matchedAmount.remainder(increment)); LOGGER.trace("matchedAmount adjusted for granularity: " + matchedAmount.toPlainString() + " " + wantAssetData.getName()); - // If we can't buy anything then we're done + // If we can't buy anything then try another order if (matchedAmount.compareTo(BigDecimal.ZERO) <= 0) - break; + continue; // Trade can go ahead! diff --git a/src/qora/at/AT.java b/src/qora/at/AT.java index 292ff62b..1eb8e762 100644 --- a/src/qora/at/AT.java +++ b/src/qora/at/AT.java @@ -1,5 +1,6 @@ package qora.at; +import java.math.BigDecimal; import java.nio.ByteBuffer; import org.ciyam.at.MachineState; @@ -7,6 +8,8 @@ import org.ciyam.at.MachineState; import data.at.ATData; import data.at.ATStateData; import data.transaction.DeployATTransactionData; +import qora.account.PublicKeyAccount; +import qora.crypto.Crypto; import repository.DataException; import repository.Repository; @@ -25,11 +28,14 @@ public class AT { this.atStateData = atStateData; } + /** Deploying AT */ public AT(Repository repository, DeployATTransactionData deployATTransactionData) throws DataException { this.repository = repository; String atAddress = deployATTransactionData.getATAddress(); - int height = this.repository.getBlockRepository().getBlockchainHeight(); + int height = this.repository.getBlockRepository().getBlockchainHeight() + 1; + String creator = new PublicKeyAccount(repository, deployATTransactionData.getCreatorPublicKey()).getAddress(); + long creation = deployATTransactionData.getTimestamp(); byte[] creationBytes = deployATTransactionData.getCreationBytes(); short version = (short) (creationBytes[0] | (creationBytes[1] << 8)); // Little-endian @@ -37,11 +43,14 @@ public class AT { if (version >= 2) { MachineState machineState = new MachineState(deployATTransactionData.getCreationBytes()); - this.atData = new ATData(atAddress, machineState.version, machineState.getCodeBytes(), machineState.getIsSleeping(), + this.atData = new ATData(atAddress, creator, creation, machineState.version, machineState.getCodeBytes(), machineState.getIsSleeping(), machineState.getSleepUntilHeight(), machineState.getIsFinished(), machineState.getHadFatalError(), machineState.getIsFrozen(), - machineState.getFrozenBalance(), deployATTransactionData.getSignature()); + machineState.getFrozenBalance()); - this.atStateData = new ATStateData(atAddress, height, machineState.toBytes()); + byte[] stateData = machineState.toBytes(); + byte[] stateHash = Crypto.digest(stateData); + + this.atStateData = new ATStateData(atAddress, height, creation, stateData, stateHash, BigDecimal.ZERO.setScale(8)); } else { // Legacy v1 AT in 'dead' state // Extract code bytes length @@ -64,10 +73,9 @@ public class AT { 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.atData = new ATData(atAddress, creator, creation, 1, codeBytes, false, null, true, false, false, (Long) null); - this.atStateData = new ATStateData(deployATTransactionData.getATAddress(), height, null); + this.atStateData = new ATStateData(atAddress, height, creation, null, null, BigDecimal.ZERO.setScale(8)); } } @@ -75,7 +83,6 @@ public class AT { public void deploy() throws DataException { this.repository.getATRepository().save(this.atData); - this.repository.getATRepository().save(this.atStateData); } public void undeploy() throws DataException { diff --git a/src/qora/block/Block.java b/src/qora/block/Block.java index 44fdea7d..1f000e1b 100644 --- a/src/qora/block/Block.java +++ b/src/qora/block/Block.java @@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger; import com.google.common.primitives.Bytes; +import data.at.ATStateData; import data.block.BlockData; import data.block.BlockTransactionData; import data.transaction.TransactionData; @@ -25,6 +26,7 @@ import qora.assets.Asset; import qora.crypto.Crypto; import qora.transaction.GenesisTransaction; import qora.transaction.Transaction; +import repository.ATRepository; import repository.BlockRepository; import repository.DataException; import repository.Repository; @@ -64,6 +66,7 @@ public class Block { REFERENCE_MISSING(10), PARENT_DOES_NOT_EXIST(11), BLOCKCHAIN_NOT_EMPTY(12), + PARENT_HAS_EXISTING_CHILD(13), TIMESTAMP_OLDER_THAN_PARENT(20), TIMESTAMP_IN_FUTURE(21), TIMESTAMP_MS_INCORRECT(22), @@ -74,7 +77,8 @@ public class Block { GENESIS_TRANSACTIONS_INVALID(50), TRANSACTION_TIMESTAMP_INVALID(51), TRANSACTION_INVALID(52), - TRANSACTION_PROCESSING_FAILED(53); + TRANSACTION_PROCESSING_FAILED(53), + AT_STATES_MISMATCH(61); public final int value; @@ -97,6 +101,11 @@ public class Block { // Other properties private static final Logger LOGGER = LogManager.getLogger(Block.class); protected List transactions; + + protected List atStates; + protected List ourAtStates; // Generated locally + protected BigDecimal ourAtFees; // Generated locally + protected BigDecimal cachedNextGeneratingBalance; // Other useful constants @@ -104,39 +113,92 @@ public class Block { // Constructors + /** + * Constructs Block-handling object without loading transactions and AT states. + *

+ * Transactions and AT states are loaded on first call to getTransactions() or getATStates() respectively. + * + * @param repository + * @param blockData + * @throws DataException + */ public Block(Repository repository, BlockData blockData) throws DataException { this.repository = repository; this.blockData = blockData; this.generator = new PublicKeyAccount(repository, blockData.getGeneratorPublicKey()); } - // When receiving a block over network? - public Block(Repository repository, BlockData blockData, List transactions) throws DataException { + /** + * Constructs Block-handling object using passed transaction and AT states. + *

+ * This constructor typically used when receiving a serialized block over the network. + * + * @param repository + * @param blockData + * @param transactions + * @param atStates + * @throws DataException + */ + public Block(Repository repository, BlockData blockData, List transactions, List atStates) throws DataException { this(repository, blockData); this.transactions = new ArrayList(); + BigDecimal totalFees = BigDecimal.ZERO.setScale(8); + // We have to sum fees too for (TransactionData transactionData : transactions) { this.transactions.add(Transaction.fromData(repository, transactionData)); - this.blockData.setTotalFees(this.blockData.getTotalFees().add(transactionData.getFee())); + totalFees = totalFees.add(transactionData.getFee()); } + + this.atStates = atStates; + for (ATStateData atState : atStates) + totalFees = totalFees.add(atState.getFees()); + + this.blockData.setTotalFees(totalFees); } - // For creating a new block? - public Block(Repository repository, int version, byte[] reference, long timestamp, BigDecimal generatingBalance, PrivateKeyAccount generator, - byte[] atBytes, BigDecimal atFees) { + /** + * Constructs Block-handling object with basic, initial values. + *

+ * This constructor typically used when generating a new block. + *

+ * Note that CIYAM ATs will be executed and AT-Transactions prepended to this block, along with AT state data and fees. + * + * @param repository + * @param version + * @param reference + * @param timestamp + * @param generatingBalance + * @param generator + * @throws DataException + */ + public Block(Repository repository, int version, byte[] reference, long timestamp, BigDecimal generatingBalance, PrivateKeyAccount generator) + throws DataException { this.repository = repository; this.generator = generator; - this.blockData = new BlockData(version, reference, 0, BigDecimal.ZERO.setScale(8), null, 0, timestamp, generatingBalance, generator.getPublicKey(), - null, atBytes, atFees); + int transactionCount = 0; + byte[] transactionsSignature = null; + Integer height = null; + byte[] generatorSignature = null; + + this.executeATs(); + + int atCount = this.ourAtStates.size(); + BigDecimal atFees = this.ourAtFees; + BigDecimal totalFees = atFees; + + this.blockData = new BlockData(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, generatingBalance, + generator.getPublicKey(), generatorSignature, atCount, atFees); this.transactions = new ArrayList(); + this.atStates = this.ourAtStates; } /** Construct a new block for use in tests */ - public Block(Repository repository, BlockData parentBlockData, PrivateKeyAccount generator, byte[] atBytes, BigDecimal atFees) throws DataException { + public Block(Repository repository, BlockData parentBlockData, PrivateKeyAccount generator) throws DataException { this.repository = repository; this.generator = generator; @@ -155,11 +217,18 @@ public class Block { } long timestamp = parentBlock.calcNextBlockTimestamp(version, generatorSignature, generator); + int transactionCount = 0; + BigDecimal totalFees = BigDecimal.ZERO.setScale(8); + byte[] transactionsSignature = null; + int height = parentBlockData.getHeight() + 1; + int atCount = 0; + BigDecimal atFees = BigDecimal.ZERO.setScale(8); - this.blockData = new BlockData(version, reference, 0, BigDecimal.ZERO.setScale(8), null, 0, timestamp, generatingBalance, generator.getPublicKey(), - generatorSignature, atBytes, atFees); + this.blockData = new BlockData(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, generatingBalance, + generator.getPublicKey(), generatorSignature, atCount, atFees); this.transactions = new ArrayList(); + this.atStates = new ArrayList(); } // Getters/setters @@ -192,12 +261,17 @@ public class Block { * @return 1, 2 or 3 */ public int getNextBlockVersion() { + if (this.blockData.getHeight() == null) + throw new IllegalStateException("Can't determine next block's version as this block has no height set"); + if (this.blockData.getHeight() < BlockChain.getATReleaseHeight()) return 1; else if (this.blockData.getTimestamp() < BlockChain.getPowFixReleaseTimestamp()) return 2; - else + else if (this.blockData.getTimestamp() < BlockChain.getDeployATV2Timestamp()) return 3; + else + return 4; } /** @@ -212,8 +286,8 @@ public class Block { * @throws DataException */ public BigDecimal calcNextBlockGeneratingBalance() throws DataException { - if (this.blockData.getHeight() == 0) - throw new IllegalStateException("Block height is unset"); + if (this.blockData.getHeight() == null) + throw new IllegalStateException("Can't calculate next block's generating balance as this block's height is unset"); // This block not at the start of an interval? if (this.blockData.getHeight() % BlockChain.BLOCK_RETARGET_INTERVAL != 0) @@ -346,7 +420,7 @@ public class Block { /** * Return block's transactions. *

- * If the block was loaded from repository then it's possible this method will call the repository to load the transactions if they are not already loaded. + * If the block was loaded from repository then it's possible this method will call the repository to fetch the transactions if not done already. * * @return * @throws DataException @@ -371,6 +445,37 @@ public class Block { return this.transactions; } + /** + * Return block's AT states. + *

+ * If the block was loaded from repository then it's possible this method will call the repository to fetch the AT states if not done already. + *

+ * Note: AT states fetched from repository only contain summary info, not actual data like serialized state data or AT creation timestamps! + * + * @return + * @throws DataException + */ + public List getATStates() throws DataException { + // Already loaded? + if (this.atStates != null) + return this.atStates; + + // If loading from repository, this block must have a height + if (this.blockData.getHeight() == null) + throw new IllegalStateException("Can't fetch block's AT states from repository without a block height"); + + // Allocate cache for results + List atStateData = this.repository.getATRepository().getBlockATStatesFromHeight(this.blockData.getHeight()); + + // The number of AT states fetched from repository should correspond with Block's atCount + if (atStateData.size() != this.blockData.getATCount()) + throw new IllegalStateException("Block's AT states from repository do not match block's AT count"); + + this.atStates = atStateData; + + return this.atStates; + } + // Navigation /** @@ -531,8 +636,6 @@ public class Block { * @throws DataException */ public ValidationResult isValid() throws DataException { - // TODO - // Check parent block exists if (this.blockData.getReference() == null) return ValidationResult.REFERENCE_MISSING; @@ -543,6 +646,10 @@ public class Block { Block parentBlock = new Block(this.repository, parentBlockData); + // Check parent doesn't already have a child block + if (parentBlock.getChild() != null) + return ValidationResult.PARENT_HAS_EXISTING_CHILD; + // Check timestamp is newer than parent timestamp if (this.blockData.getTimestamp() <= parentBlockData.getTimestamp()) return ValidationResult.TIMESTAMP_OLDER_THAN_PARENT; @@ -558,7 +665,7 @@ public class Block { // Check block version if (this.blockData.getVersion() != parentBlock.getNextBlockVersion()) return ValidationResult.VERSION_INCORRECT; - if (this.blockData.getVersion() < 2 && (this.blockData.getAtBytes() != null || this.blockData.getAtFees() != null)) + if (this.blockData.getVersion() < 2 && this.blockData.getATCount() != 0) return ValidationResult.FEATURE_NOT_YET_RELEASED; // Check generating balance @@ -583,16 +690,34 @@ public class Block { if (hashValue.compareTo(lowerTarget) < 0) return ValidationResult.GENERATOR_NOT_ACCEPTED; - // Process CIYAM ATs, prepending AT-Transactions to block then compare post-execution checksums - // XXX We should pre-calculate, and cache, next block's AT-transactions after processing each block to save repeated work - if (this.blockData.getAtBytes() != null && this.blockData.getAtBytes().length > 0) { - // TODO - // try { - // AT_Block atBlock = AT_Controller.validateATs(this.getBlockATs(), BlockChain.getHeight() + 1); - // this.atFees = atBlock.getTotalFees(); - // } catch (NoSuchAlgorithmException | AT_Exception e) { - // return false; - // } + // CIYAM ATs + if (this.blockData.getATCount() != 0) { + // Locally generated AT states should be valid so no need to re-execute them + if (this.ourAtStates != this.getATStates()) { + // Otherwise, check locally generated AT states against ones received from elsewhere? + this.executeATs(); + + if (this.ourAtStates.size() != this.blockData.getATCount()) + return ValidationResult.AT_STATES_MISMATCH; + + if (this.ourAtFees.compareTo(this.blockData.getATFees()) != 0) + return ValidationResult.AT_STATES_MISMATCH; + + // Note: this.atStates fully loaded thanks to this.getATStates() call above + for (int s = 0; s < this.atStates.size(); ++s) { + ATStateData ourAtState = this.ourAtStates.get(s); + ATStateData theirAtState = this.atStates.get(s); + + if (!ourAtState.getATAddress().equals(theirAtState.getATAddress())) + return ValidationResult.AT_STATES_MISMATCH; + + if (!ourAtState.getStateHash().equals(theirAtState.getStateHash())) + return ValidationResult.AT_STATES_MISMATCH; + + if (ourAtState.getFees().compareTo(theirAtState.getFees()) != 0) + return ValidationResult.AT_STATES_MISMATCH; + } + } } // Check transactions @@ -643,8 +768,47 @@ public class Block { return ValidationResult.OK; } + /** + * Execute CIYAM ATs for this block. + *

+ * This needs to be done locally for all blocks, regardless of origin.
+ * This method is called by isValid. + *

+ * After calling, AT-generated transactions are prepended to the block's transactions and AT state data is generated. + *

+ * This method is not needed if fetching an existing block from the repository. + *

+ * Updates this.ourAtStates and this.ourAtFees. + * + * @see #isValid() + * + * @throws DataException + * + */ + public void executeATs() throws DataException { + // We're expecting a lack of AT state data at this point. + if (this.ourAtStates != null) + throw new IllegalStateException("Attempted to execute ATs when block's local AT state data already exists"); + + // For old v1 CIYAM ATs we blindly accept them + if (this.blockData.getVersion() < 4) { + this.ourAtStates = this.atStates; + this.ourAtFees = this.blockData.getATFees(); + return; + } + + // Find all executable ATs, ordered by earliest creation date first + + // Run each AT, appends AT-Transactions and corresponding AT states, to our lists + + // Finally prepend our entire AT-Transactions/states to block's transactions/states, adjust fees, etc. + + // Note: store locally-calculated AT states separately to this.atStates so we can compare them in isValid() + } + public void process() throws DataException { // Process transactions (we'll link them to this block after saving the block itself) + // AT-generated transactions are already added to our transactions so no special handling is needed here. List transactions = this.getTransactions(); for (Transaction transaction : transactions) transaction.process(); @@ -654,6 +818,17 @@ public class Block { if (blockFee.compareTo(BigDecimal.ZERO) > 0) this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(blockFee)); + // Process AT fees and save AT states into repository + ATRepository atRepository = this.repository.getATRepository(); + for (ATStateData atState : this.getATStates()) { + Account atAccount = new Account(this.repository, atState.getATAddress()); + + // Subtract AT-generated fees from AT accounts + atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).subtract(atState.getFees())); + + atRepository.save(atState); + } + // Link block into blockchain by fetching signature of highest block and setting that as our reference int blockchainHeight = this.repository.getBlockRepository().getBlockchainHeight(); BlockData latestBlockData = this.repository.getBlockRepository().fromHeight(blockchainHeight); @@ -675,12 +850,8 @@ public class Block { } public void orphan() throws DataException { - // TODO - - // Orphan block's CIYAM ATs - orphanAutomatedTransactions(); - // Orphan transactions in reverse order, and unlink them from this block + // AT-generated transactions are already added to our transactions so no special handling is needed here. List transactions = this.getTransactions(); for (int sequence = transactions.size() - 1; sequence >= 0; --sequence) { Transaction transaction = transactions.get(sequence); @@ -696,25 +867,19 @@ public class Block { if (blockFee.compareTo(BigDecimal.ZERO) > 0) this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFee)); + // Return AT fees and delete AT states from repository + ATRepository atRepository = this.repository.getATRepository(); + for (ATStateData atState : this.getATStates()) { + Account atAccount = new Account(this.repository, atState.getATAddress()); + + // Return AT-generated fees to AT accounts + atAccount.setConfirmedBalance(Asset.QORA, atAccount.getConfirmedBalance(Asset.QORA).add(atState.getFees())); + } + // Delete ATStateData for this height + atRepository.deleteATStates(this.blockData.getHeight()); + // Delete block from blockchain this.repository.getBlockRepository().delete(this.blockData); } - public void orphanAutomatedTransactions() throws DataException { - // TODO - CIYAM AT support - /* - * LinkedHashMap< Tuple2 , AT_Transaction > atTxs = DBSet.getInstance().getATTransactionMap().getATTransactions(this.getHeight(db)); - * - * Iterator 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 ); - * - * } - */ - } - } diff --git a/src/qora/block/GenesisBlock.java b/src/qora/block/GenesisBlock.java index 9daab7b6..0d309dd4 100644 --- a/src/qora/block/GenesisBlock.java +++ b/src/qora/block/GenesisBlock.java @@ -34,7 +34,7 @@ public class GenesisBlock extends Block { public GenesisBlock(Repository repository) throws DataException { super(repository, new BlockData(GENESIS_BLOCK_VERSION, GENESIS_REFERENCE, 0, BigDecimal.ZERO.setScale(8), GENESIS_TRANSACTIONS_SIGNATURE, 1, - Settings.getInstance().getGenesisTimestamp(), GENESIS_GENERATING_BALANCE, GENESIS_GENERATOR_PUBLIC_KEY, GENESIS_GENERATOR_SIGNATURE, null, null)); + Settings.getInstance().getGenesisTimestamp(), GENESIS_GENERATING_BALANCE, GENESIS_GENERATOR_PUBLIC_KEY, GENESIS_GENERATOR_SIGNATURE, 0, BigDecimal.ZERO.setScale(8))); this.transactions = new ArrayList(); diff --git a/src/qora/payment/Payment.java b/src/qora/payment/Payment.java index fbf0899f..66e2175d 100644 --- a/src/qora/payment/Payment.java +++ b/src/qora/payment/Payment.java @@ -46,31 +46,31 @@ public class Payment { amountsByAssetId.put(Asset.QORA, fee); // Check payments, and calculate amount total by assetId - if (payments != null) - for (PaymentData paymentData : payments) { - // Check amount is positive - if (paymentData.getAmount().compareTo(BigDecimal.ZERO) < 0) - return ValidationResult.NEGATIVE_AMOUNT; + for (PaymentData paymentData : payments) { + // Check amount is zero or positive + if (paymentData.getAmount().compareTo(BigDecimal.ZERO) < 0) + return ValidationResult.NEGATIVE_AMOUNT; - // Optional zero-amount check - if (!isZeroAmountValid && paymentData.getAmount().compareTo(BigDecimal.ZERO) <= 0) - return ValidationResult.NEGATIVE_AMOUNT; + // Optional zero-amount check + if (!isZeroAmountValid && paymentData.getAmount().compareTo(BigDecimal.ZERO) <= 0) + return ValidationResult.NEGATIVE_AMOUNT; - // Check recipient address is valid - if (!Crypto.isValidAddress(paymentData.getRecipient())) - return ValidationResult.INVALID_ADDRESS; + // Check recipient address is valid + if (!Crypto.isValidAddress(paymentData.getRecipient())) + return ValidationResult.INVALID_ADDRESS; - AssetData assetData = assetRepository.fromAssetId(paymentData.getAssetId()); - // Check asset even exists - if (assetData == null) - return ValidationResult.ASSET_DOES_NOT_EXIST; + AssetData assetData = assetRepository.fromAssetId(paymentData.getAssetId()); + // Check asset even exists + if (assetData == null) + return ValidationResult.ASSET_DOES_NOT_EXIST; - // Check asset amount is integer if asset is not divisible - if (!assetData.getIsDivisible() && paymentData.getAmount().stripTrailingZeros().scale() > 0) - return ValidationResult.INVALID_AMOUNT; + // Check asset amount is integer if asset is not divisible + if (!assetData.getIsDivisible() && paymentData.getAmount().stripTrailingZeros().scale() > 0) + return ValidationResult.INVALID_AMOUNT; - amountsByAssetId.compute(paymentData.getAssetId(), (assetId, amount) -> amount == null ? amount : amount.add(paymentData.getAmount())); - } + // Set or add amount into amounts-by-asset map + amountsByAssetId.compute(paymentData.getAssetId(), (assetId, amount) -> amount == null ? amount : amount.add(paymentData.getAmount())); + } // Check sender has enough of each asset Account sender = new PublicKeyAccount(this.repository, senderPublicKey); @@ -87,7 +87,7 @@ public class Payment { // Single payment forms public ValidationResult isValid(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, boolean isZeroAmountValid) throws DataException { - return isValid(senderPublicKey, Collections.singletonList(paymentData), fee); + return isValid(senderPublicKey, Collections.singletonList(paymentData), fee, isZeroAmountValid); } public ValidationResult isValid(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee) throws DataException { @@ -105,22 +105,22 @@ public class Payment { sender.setLastReference(signature); // Process all payments - if (payments != null) - for (PaymentData paymentData : payments) { - Account recipient = new Account(this.repository, paymentData.getRecipient()); - long assetId = paymentData.getAssetId(); - BigDecimal amount = paymentData.getAmount(); + for (PaymentData paymentData : payments) { + Account recipient = new Account(this.repository, paymentData.getRecipient()); - // Update sender's balance due to amount - sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(amount)); + long assetId = paymentData.getAssetId(); + BigDecimal amount = paymentData.getAmount(); - // Update recipient's balance - recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount)); + // Update sender's balance due to amount + sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(amount)); - // For QORA amounts only: if recipient has no reference yet, then this is their starting reference - if ((alwaysInitializeRecipientReference || assetId == Asset.QORA) && recipient.getLastReference() == null) - recipient.setLastReference(signature); - } + // Update recipient's balance + recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount)); + + // For QORA amounts only: if recipient has no reference yet, then this is their starting reference + if ((alwaysInitializeRecipientReference || assetId == Asset.QORA) && recipient.getLastReference() == null) + recipient.setLastReference(signature); + } } public void process(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, boolean alwaysInitializeRecipientReference) @@ -139,25 +139,24 @@ public class Payment { sender.setLastReference(reference); // Orphan all payments - if (payments != null) - for (PaymentData paymentData : payments) { - Account recipient = new Account(this.repository, paymentData.getRecipient()); - long assetId = paymentData.getAssetId(); - BigDecimal amount = paymentData.getAmount(); + for (PaymentData paymentData : payments) { + Account recipient = new Account(this.repository, paymentData.getRecipient()); + long assetId = paymentData.getAssetId(); + BigDecimal amount = paymentData.getAmount(); - // Update sender's balance due to amount - sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).add(amount)); + // Update sender's balance due to amount + sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).add(amount)); - // Update recipient's balance - recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(amount)); + // Update recipient's balance + recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(amount)); - /* - * For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own - * (which would have changed their last reference) thus this is their first reference so remove it. - */ - if ((alwaysUninitializeRecipientReference || assetId == Asset.QORA) && Arrays.equals(recipient.getLastReference(), signature)) - recipient.setLastReference(null); - } + /* + * For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own + * (which would have changed their last reference) thus this is their first reference so remove it. + */ + if ((alwaysUninitializeRecipientReference || assetId == Asset.QORA) && Arrays.equals(recipient.getLastReference(), signature)) + recipient.setLastReference(null); + } } public void orphan(byte[] senderPublicKey, PaymentData paymentData, BigDecimal fee, byte[] signature, byte[] reference, diff --git a/src/qora/transaction/ATTransaction.java b/src/qora/transaction/ATTransaction.java index e3be08e9..790ba578 100644 --- a/src/qora/transaction/ATTransaction.java +++ b/src/qora/transaction/ATTransaction.java @@ -5,13 +5,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import data.PaymentData; +import data.assets.AssetData; 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 qora.crypto.Crypto; import repository.DataException; import repository.Repository; @@ -35,17 +34,17 @@ public class ATTransaction extends Transaction { @Override public List getRecipientAccounts() throws DataException { - return Collections.singletonList(new Account(this.repository, atTransactionData.getRecipient())); + return Collections.singletonList(new Account(this.repository, this.atTransactionData.getRecipient())); } @Override public boolean isInvolved(Account account) throws DataException { String address = account.getAddress(); - if (address.equals(this.getSender().getAddress())) + if (address.equals(this.atTransactionData.getATAddress())) return true; - if (address.equals(atTransactionData.getRecipient())) + if (address.equals(this.atTransactionData.getRecipient())) return true; return false; @@ -55,52 +54,73 @@ public class ATTransaction extends Transaction { public BigDecimal getAmount(Account account) throws DataException { String address = account.getAddress(); BigDecimal amount = BigDecimal.ZERO.setScale(8); - String senderAddress = this.getSender().getAddress(); + String atAddress = this.atTransactionData.getATAddress(); - if (address.equals(senderAddress)) { + if (address.equals(atAddress)) { amount = amount.subtract(this.atTransactionData.getFee()); - if (atTransactionData.getAmount() != null && atTransactionData.getAssetId() == Asset.QORA) - amount = amount.subtract(atTransactionData.getAmount()); + if (this.atTransactionData.getAmount() != null && this.atTransactionData.getAssetId() == Asset.QORA) + amount = amount.subtract(this.atTransactionData.getAmount()); } - if (address.equals(atTransactionData.getRecipient()) && atTransactionData.getAmount() != null) - amount = amount.add(atTransactionData.getAmount()); + if (address.equals(this.atTransactionData.getRecipient()) && this.atTransactionData.getAmount() != null) + amount = amount.add(this.atTransactionData.getAmount()); return amount; } // Navigation - public Account getSender() throws DataException { - return new PublicKeyAccount(this.repository, this.atTransactionData.getSenderPublicKey()); + public Account getATAccount() throws DataException { + return new Account(this.repository, this.atTransactionData.getATAddress()); + } + + public Account getRecipient() throws DataException { + return new Account(this.repository, this.atTransactionData.getRecipient()); } // 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())) + Account atAccount = getATAccount(); + if (!Arrays.equals(atAccount.getLastReference(), atTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; if (this.atTransactionData.getMessage().length > MAX_DATA_SIZE) return ValidationResult.INVALID_DATA_LENGTH; + BigDecimal amount = this.atTransactionData.getAmount(); + // If we have no payment then we're done - if (this.atTransactionData.getAmount() == null) + if (amount == null) return ValidationResult.OK; - // Wrap and delegate final payment checks to Payment class - return new Payment(this.repository).isValid(atTransactionData.getSenderPublicKey(), getPaymentData(), atTransactionData.getFee()); + // Check amount is zero or positive + if (amount.compareTo(BigDecimal.ZERO) < 0) + return ValidationResult.NEGATIVE_AMOUNT; + + // Check recipient address is valid + if (!Crypto.isValidAddress(this.atTransactionData.getRecipient())) + return ValidationResult.INVALID_ADDRESS; + + long assetId = this.atTransactionData.getAssetId(); + AssetData assetData = this.repository.getAssetRepository().fromAssetId(assetId); + // Check asset even exists + if (assetData == null) + return ValidationResult.ASSET_DOES_NOT_EXIST; + + // Check asset amount is integer if asset is not divisible + if (!assetData.getIsDivisible() && amount.stripTrailingZeros().scale() > 0) + return ValidationResult.INVALID_AMOUNT; + + Account sender = getATAccount(); + // Check sender has enough of asset + if (sender.getConfirmedBalance(assetId).compareTo(amount) < 0) + return ValidationResult.NO_BALANCE; + + return ValidationResult.OK; } @Override @@ -108,10 +128,25 @@ public class ATTransaction extends Transaction { // 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); + if (this.atTransactionData.getAmount() != null) { + Account sender = getATAccount(); + Account recipient = getRecipient(); + + long assetId = this.atTransactionData.getAssetId(); + BigDecimal amount = this.atTransactionData.getAmount(); + + // Update sender's balance due to amount + sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).subtract(amount)); + + // Update recipient's balance + recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).add(amount)); + + // For QORA amounts only: if recipient has no reference yet, then this is their starting reference + if (assetId == Asset.QORA && recipient.getLastReference() == null) + // In Qora1 last reference was set to 64-bytes of zero + // In Qora2 we use AT-Transction's signature, which makes more sense + recipient.setLastReference(this.atTransactionData.getSignature()); + } } @Override @@ -119,10 +154,26 @@ public class ATTransaction extends Transaction { // 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); + if (this.atTransactionData.getAmount() != null) { + Account sender = getATAccount(); + Account recipient = getRecipient(); + + long assetId = this.atTransactionData.getAssetId(); + BigDecimal amount = this.atTransactionData.getAmount(); + + // Update sender's balance due to amount + sender.setConfirmedBalance(assetId, sender.getConfirmedBalance(assetId).add(amount)); + + // Update recipient's balance + recipient.setConfirmedBalance(assetId, recipient.getConfirmedBalance(assetId).subtract(amount)); + + /* + * For QORA amounts only: If recipient's last reference is this transaction's signature, then they can't have made any transactions of their own + * (which would have changed their last reference) thus this is their first reference so remove it. + */ + if (assetId == Asset.QORA && Arrays.equals(recipient.getLastReference(), this.atTransactionData.getSignature())) + recipient.setLastReference(null); + } } } diff --git a/src/qora/transaction/ArbitraryTransaction.java b/src/qora/transaction/ArbitraryTransaction.java index 92d7f07b..ef82afaa 100644 --- a/src/qora/transaction/ArbitraryTransaction.java +++ b/src/qora/transaction/ArbitraryTransaction.java @@ -149,9 +149,9 @@ public class ArbitraryTransaction extends Transaction { // Make sure directory structure exists try { Files.createDirectories(dataPath.getParent()); - } catch (IOException e1) { + } catch (IOException e) { // TODO Auto-generated catch block - e1.printStackTrace(); + e.printStackTrace(); } // Output actual transaction data diff --git a/src/qora/transaction/DeployATTransaction.java b/src/qora/transaction/DeployATTransaction.java index 699b0654..e80412bf 100644 --- a/src/qora/transaction/DeployATTransaction.java +++ b/src/qora/transaction/DeployATTransaction.java @@ -205,7 +205,6 @@ public class DeployATTransaction extends Transaction { // Update AT's balance atAccount.setConfirmedBalance(Asset.QORA, deployATTransactionData.getAmount()); - } @Override diff --git a/src/qora/transaction/GenesisTransaction.java b/src/qora/transaction/GenesisTransaction.java index d3ae1bc1..3a1a83e9 100644 --- a/src/qora/transaction/GenesisTransaction.java +++ b/src/qora/transaction/GenesisTransaction.java @@ -133,12 +133,13 @@ public class GenesisTransaction extends Transaction { // Save this transaction itself this.repository.getTransactionRepository().save(this.transactionData); - // Update recipient's balance Account recipient = new Account(repository, genesisTransactionData.getRecipient()); - recipient.setConfirmedBalance(Asset.QORA, genesisTransactionData.getAmount()); - // Set recipient's starting reference + // Set recipient's starting reference (also creates account) recipient.setLastReference(genesisTransactionData.getSignature()); + + // Update recipient's balance + recipient.setConfirmedBalance(Asset.QORA, genesisTransactionData.getAmount()); } @Override @@ -146,12 +147,8 @@ public class GenesisTransaction extends Transaction { // Delete this transaction this.repository.getTransactionRepository().delete(this.transactionData); - // Delete recipient's balance - Account recipient = new Account(repository, genesisTransactionData.getRecipient()); - recipient.deleteBalance(Asset.QORA); - - // Delete recipient's last reference - recipient.setLastReference(null); + // Delete recipient's account (and balance) + this.repository.getAccountRepository().delete(genesisTransactionData.getRecipient()); } } diff --git a/src/qora/transaction/MessageTransaction.java b/src/qora/transaction/MessageTransaction.java index b01dcd3b..abc93d0a 100644 --- a/src/qora/transaction/MessageTransaction.java +++ b/src/qora/transaction/MessageTransaction.java @@ -85,7 +85,7 @@ public class MessageTransaction extends Transaction { // Processing private PaymentData getPaymentData() { - return new PaymentData(messageTransactionData.getRecipient(), Asset.QORA, messageTransactionData.getAmount()); + return new PaymentData(messageTransactionData.getRecipient(), messageTransactionData.getAssetId(), messageTransactionData.getAmount()); } @Override diff --git a/src/repository/ATRepository.java b/src/repository/ATRepository.java index fef0c76e..70e494ef 100644 --- a/src/repository/ATRepository.java +++ b/src/repository/ATRepository.java @@ -1,5 +1,7 @@ package repository; +import java.util.List; + import data.at.ATData; import data.at.ATStateData; @@ -17,8 +19,14 @@ public interface ATRepository { public ATStateData getATState(String atAddress, int height) throws DataException; + public List getBlockATStatesFromHeight(int height) throws DataException; + public void save(ATStateData atStateData) throws DataException; + /** Delete AT's state data at this height */ public void delete(String atAddress, int height) throws DataException; + /** Delete state data for all ATs at this height */ + public void deleteATStates(int height) throws DataException; + } diff --git a/src/repository/AccountRepository.java b/src/repository/AccountRepository.java index 5983ebfb..d4356a60 100644 --- a/src/repository/AccountRepository.java +++ b/src/repository/AccountRepository.java @@ -7,6 +7,8 @@ public interface AccountRepository { // General account + public void create(String address) throws DataException; + public AccountData getAccount(String address) throws DataException; public void save(AccountData accountData) throws DataException; diff --git a/src/repository/hsqldb/HSQLDBATRepository.java b/src/repository/hsqldb/HSQLDBATRepository.java index 4cb0cd23..a634fe98 100644 --- a/src/repository/hsqldb/HSQLDBATRepository.java +++ b/src/repository/hsqldb/HSQLDBATRepository.java @@ -3,6 +3,10 @@ package repository.hsqldb; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; import data.at.ATData; import data.at.ATStateData; @@ -21,30 +25,32 @@ public class HSQLDBATRepository implements ATRepository { @Override public ATData fromATAddress(String atAddress) throws DataException { - try (ResultSet resultSet = this.repository - .checkedExecute("SELECT owner, asset_name, description, quantity, is_divisible, reference FROM Assets WHERE AT_address = ?", atAddress)) { + try (ResultSet resultSet = this.repository.checkedExecute( + "SELECT creator, creation, version, code_bytes, is_sleeping, sleep_until_height, is_finished, had_fatal_error, is_frozen, frozen_balance FROM ATs WHERE AT_address = ?", + atAddress)) { if (resultSet == null) return null; - int version = resultSet.getInt(1); - byte[] codeBytes = resultSet.getBytes(2); // Actually BLOB - boolean isSleeping = resultSet.getBoolean(3); + String creator = resultSet.getString(1); + long creation = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + int version = resultSet.getInt(3); + byte[] codeBytes = resultSet.getBytes(4); // Actually BLOB + boolean isSleeping = resultSet.getBoolean(5); - Integer sleepUntilHeight = resultSet.getInt(4); + Integer sleepUntilHeight = resultSet.getInt(6); if (resultSet.wasNull()) sleepUntilHeight = null; - boolean isFinished = resultSet.getBoolean(5); - boolean hadFatalError = resultSet.getBoolean(6); - boolean isFrozen = resultSet.getBoolean(7); + boolean isFinished = resultSet.getBoolean(7); + boolean hadFatalError = resultSet.getBoolean(8); + boolean isFrozen = resultSet.getBoolean(9); - BigDecimal frozenBalance = resultSet.getBigDecimal(8); + BigDecimal frozenBalance = resultSet.getBigDecimal(10); if (resultSet.wasNull()) frozenBalance = null; - byte[] deploySignature = resultSet.getBytes(9); - - return new ATData(atAddress, version, codeBytes, isSleeping, sleepUntilHeight, isFinished, hadFatalError, isFrozen, frozenBalance, deploySignature); + return new ATData(atAddress, creator, creation, version, codeBytes, isSleeping, sleepUntilHeight, isFinished, hadFatalError, isFrozen, + frozenBalance); } catch (SQLException e) { throw new DataException("Unable to fetch AT from repository", e); } @@ -54,10 +60,10 @@ public class HSQLDBATRepository implements ATRepository { public void save(ATData atData) throws DataException { HSQLDBSaver saveHelper = new HSQLDBSaver("ATs"); - saveHelper.bind("AT_address", atData.getATAddress()).bind("version", atData.getVersion()).bind("code_bytes", atData.getCodeBytes()) - .bind("is_sleeping", atData.getIsSleeping()).bind("sleep_until_height", atData.getSleepUntilHeight()) - .bind("is_finished", atData.getIsFinished()).bind("had_fatal_error", atData.getHadFatalError()).bind("is_frozen", atData.getIsFrozen()) - .bind("frozen_balance", atData.getFrozenBalance()).bind("deploy_signature", atData.getDeploySignature()); + saveHelper.bind("AT_address", atData.getATAddress()).bind("creator", atData.getCreator()).bind("creation", new Timestamp(atData.getCreation())) + .bind("version", atData.getVersion()).bind("code_bytes", atData.getCodeBytes()).bind("is_sleeping", atData.getIsSleeping()) + .bind("sleep_until_height", atData.getSleepUntilHeight()).bind("is_finished", atData.getIsFinished()) + .bind("had_fatal_error", atData.getHadFatalError()).bind("is_frozen", atData.getIsFrozen()).bind("frozen_balance", atData.getFrozenBalance()); try { saveHelper.execute(this.repository); @@ -80,28 +86,63 @@ public class HSQLDBATRepository implements ATRepository { @Override public ATStateData getATState(String atAddress, int height) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT state_data FROM ATStates WHERE AT_address = ? AND height = ?", atAddress, height)) { + try (ResultSet resultSet = this.repository + .checkedExecute("SELECT creation, state_data, state_hash, fees FROM ATStates WHERE AT_address = ? AND height = ?", atAddress, height)) { if (resultSet == null) return null; - byte[] stateData = resultSet.getBytes(1); // Actually BLOB + long creation = resultSet.getTimestamp(1, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + byte[] stateData = resultSet.getBytes(2); // Actually BLOB + byte[] stateHash = resultSet.getBytes(3); + BigDecimal fees = resultSet.getBigDecimal(4); - return new ATStateData(atAddress, height, stateData); + return new ATStateData(atAddress, height, creation, stateData, stateHash, fees); } catch (SQLException e) { - throw new DataException("Unable to fetch AT State from repository", e); + throw new DataException("Unable to fetch AT state from repository", e); } } + @Override + public List getBlockATStatesFromHeight(int height) throws DataException { + List atStates = new ArrayList(); + + try (ResultSet resultSet = this.repository.checkedExecute("SELECT AT_address, state_hash, fees FROM ATStates WHERE height = ? ORDER BY creation ASC", + height)) { + if (resultSet == null) + return atStates; // No atStates in this block + + // NB: do-while loop because .checkedExecute() implicitly calls ResultSet.next() for us + do { + String atAddress = resultSet.getString(1); + byte[] stateHash = resultSet.getBytes(2); + BigDecimal fees = resultSet.getBigDecimal(3); + + ATStateData atStateData = new ATStateData(atAddress, height, stateHash, fees); + atStates.add(atStateData); + } while (resultSet.next()); + } catch (SQLException e) { + throw new DataException("Unable to fetch AT states for this height from repository", e); + } + + return atStates; + } + @Override public void save(ATStateData atStateData) throws DataException { + // We shouldn't ever save partial ATStateData + if (atStateData.getCreation() == null || atStateData.getStateHash() == null || atStateData.getHeight() == null) + throw new IllegalArgumentException("Refusing to save partial AT state into repository!"); + HSQLDBSaver saveHelper = new HSQLDBSaver("ATStates"); - saveHelper.bind("AT_address", atStateData.getATAddress()).bind("height", atStateData.getHeight()).bind("state_data", atStateData.getStateData()); + saveHelper.bind("AT_address", atStateData.getATAddress()).bind("height", atStateData.getHeight()) + .bind("creation", new Timestamp(atStateData.getCreation())).bind("state_data", atStateData.getStateData()) + .bind("state_hash", atStateData.getStateHash()).bind("fees", atStateData.getFees()); try { saveHelper.execute(this.repository); } catch (SQLException e) { - throw new DataException("Unable to save AT State into repository", e); + throw new DataException("Unable to save AT state into repository", e); } } @@ -110,7 +151,16 @@ public class HSQLDBATRepository implements ATRepository { try { this.repository.delete("ATStates", "AT_address = ? AND height = ?", atAddress, height); } catch (SQLException e) { - throw new DataException("Unable to delete AT State from repository", e); + throw new DataException("Unable to delete AT state from repository", e); + } + } + + @Override + public void deleteATStates(int height) throws DataException { + try { + this.repository.delete("ATStates", "height = ?", height); + } catch (SQLException e) { + throw new DataException("Unable to delete AT states from repository", e); } } diff --git a/src/repository/hsqldb/HSQLDBAccountRepository.java b/src/repository/hsqldb/HSQLDBAccountRepository.java index d56604b3..5c716863 100644 --- a/src/repository/hsqldb/HSQLDBAccountRepository.java +++ b/src/repository/hsqldb/HSQLDBAccountRepository.java @@ -19,6 +19,19 @@ public class HSQLDBAccountRepository implements AccountRepository { // General account + @Override + public void create(String address) throws DataException { + HSQLDBSaver saveHelper = new HSQLDBSaver("Accounts"); + + saveHelper.bind("account", address); + + try { + saveHelper.execute(this.repository); + } catch (SQLException e) { + throw new DataException("Unable to create account in repository", e); + } + } + @Override public AccountData getAccount(String address) throws DataException { try (ResultSet resultSet = this.repository.checkedExecute("SELECT reference FROM Accounts WHERE account = ?", address)) { @@ -34,6 +47,7 @@ public class HSQLDBAccountRepository implements AccountRepository { @Override public void save(AccountData accountData) throws DataException { HSQLDBSaver saveHelper = new HSQLDBSaver("Accounts"); + saveHelper.bind("account", accountData.getAddress()).bind("reference", accountData.getReference()); try { @@ -73,6 +87,7 @@ public class HSQLDBAccountRepository implements AccountRepository { @Override public void save(AccountBalanceData accountBalanceData) throws DataException { HSQLDBSaver saveHelper = new HSQLDBSaver("AccountBalances"); + saveHelper.bind("account", accountBalanceData.getAddress()).bind("asset_id", accountBalanceData.getAssetId()).bind("balance", accountBalanceData.getBalance()); diff --git a/src/repository/hsqldb/HSQLDBBlockRepository.java b/src/repository/hsqldb/HSQLDBBlockRepository.java index 6b17aa30..96119aae 100644 --- a/src/repository/hsqldb/HSQLDBBlockRepository.java +++ b/src/repository/hsqldb/HSQLDBBlockRepository.java @@ -18,7 +18,7 @@ import repository.TransactionRepository; public class HSQLDBBlockRepository implements BlockRepository { 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"; + + "transactions_signature, height, generation, generating_balance, generator, generator_signature, AT_count, AT_fees"; protected HSQLDBRepository repository; @@ -41,11 +41,11 @@ public class HSQLDBBlockRepository implements BlockRepository { BigDecimal generatingBalance = resultSet.getBigDecimal(8); byte[] generatorPublicKey = resultSet.getBytes(9); byte[] generatorSignature = resultSet.getBytes(10); - byte[] atBytes = resultSet.getBytes(11); + int atCount = resultSet.getInt(11); BigDecimal atFees = resultSet.getBigDecimal(12); return new BlockData(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, generatingBalance, - generatorPublicKey, generatorSignature, atBytes, atFees); + generatorPublicKey, generatorSignature, atCount, atFees); } catch (SQLException e) { throw new DataException("Error extracting data from result set", e); } @@ -62,7 +62,7 @@ public class HSQLDBBlockRepository implements BlockRepository { @Override public BlockData fromReference(byte[] reference) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks WHERE height = ?", reference)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT " + BLOCK_DB_COLUMNS + " FROM Blocks WHERE reference = ?", reference)) { return getBlockFromResultSet(resultSet); } catch (SQLException e) { throw new DataException("Error loading data from DB", e); @@ -123,7 +123,7 @@ public class HSQLDBBlockRepository implements BlockRepository { transactions.add(transactionRepo.fromSignature(transactionSignature)); } while (resultSet.next()); } catch (SQLException e) { - throw new DataException(e); + throw new DataException("Unable to fetch block's transactions from repository", e); } return transactions; @@ -138,7 +138,7 @@ public class HSQLDBBlockRepository implements BlockRepository { .bind("transactions_signature", blockData.getTransactionsSignature()).bind("height", blockData.getHeight()) .bind("generation", new Timestamp(blockData.getTimestamp())).bind("generating_balance", blockData.getGeneratingBalance()) .bind("generator", blockData.getGeneratorPublicKey()).bind("generator_signature", blockData.getGeneratorSignature()) - .bind("AT_data", blockData.getAtBytes()).bind("AT_fees", blockData.getAtFees()); + .bind("AT_count", blockData.getATCount()).bind("AT_fees", blockData.getATFees()); try { saveHelper.execute(this.repository); @@ -159,6 +159,7 @@ public class HSQLDBBlockRepository implements BlockRepository { @Override public void save(BlockTransactionData blockTransactionData) throws DataException { HSQLDBSaver saveHelper = new HSQLDBSaver("BlockTransactions"); + saveHelper.bind("block_signature", blockTransactionData.getBlockSignature()).bind("sequence", blockTransactionData.getSequence()) .bind("transaction_signature", blockTransactionData.getTransactionSignature()); diff --git a/src/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/repository/hsqldb/HSQLDBDatabaseUpdates.java index e8efb45a..8d4742cf 100644 --- a/src/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -85,7 +85,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TYPE Signature AS VARBINARY(64)"); stmt.execute("CREATE TYPE QoraAddress AS VARCHAR(36)"); stmt.execute("CREATE TYPE QoraPublicKey AS VARBINARY(32)"); - stmt.execute("CREATE TYPE QoraAmount AS DECIMAL(19, 8)"); + stmt.execute("CREATE TYPE QoraAmount AS DECIMAL(27, 8)"); stmt.execute("CREATE TYPE RegisteredName AS VARCHAR(400) COLLATE SQL_TEXT_NO_PAD"); stmt.execute("CREATE TYPE NameData AS VARCHAR(4000)"); stmt.execute("CREATE TYPE PollName AS VARCHAR(400) COLLATE SQL_TEXT_NO_PAD"); @@ -108,7 +108,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TABLE Blocks (signature BlockSignature PRIMARY KEY, version TINYINT NOT NULL, reference BlockSignature, " + "transaction_count INTEGER NOT NULL, total_fees QoraAmount NOT NULL, transactions_signature Signature NOT NULL, " + "height INTEGER NOT NULL, generation TIMESTAMP WITH TIME ZONE NOT NULL, generating_balance QoraAmount NOT NULL, " - + "generator QoraPublicKey NOT NULL, generator_signature Signature NOT NULL, AT_data VARBINARY(20000), AT_fees QoraAmount)"); + + "generator QoraPublicKey NOT NULL, generator_signature Signature NOT NULL, AT_count INTEGER NOT NULL, AT_fees QoraAmount NOT NULL)"); // For finding blocks by height. stmt.execute("CREATE INDEX BlockHeightIndex ON Blocks (height)"); // For finding blocks by the account that generated them. @@ -353,18 +353,21 @@ public class HSQLDBDatabaseUpdates { case 27: // CIYAM Automated Transactions - stmt.execute("CREATE TABLE ATs (AT_address QoraAddress, version INTEGER NOT NULL, code_bytes ATCode NOT NULL, " - + "is_sleeping BOOLEAN NOT NULL, sleep_until_height INTEGER, is_finished BOOLEAN NOT NULL, had_fatal_error BOOLEAN NOT NULL, " - + "is_frozen BOOLEAN NOT NULL, frozen_balance QoraAmount, deploy_signature Signature NOT NULL, PRIMARY key (AT_address))"); - // For finding executable ATs - stmt.execute("CREATE INDEX ATIndex on ATs (is_finished, AT_address)"); + stmt.execute("CREATE TABLE ATs (AT_address QoraAddress, creator QoraAddress, creation TIMESTAMP WITH TIME ZONE, version INTEGER NOT NULL, " + + "code_bytes ATCode NOT NULL, is_sleeping BOOLEAN NOT NULL, sleep_until_height INTEGER, " + + "is_finished BOOLEAN NOT NULL, had_fatal_error BOOLEAN NOT NULL, is_frozen BOOLEAN NOT NULL, frozen_balance QoraAmount, " + + "PRIMARY key (AT_address))"); + // For finding executable ATs, ordered by creation timestamp + stmt.execute("CREATE INDEX ATIndex on ATs (is_finished, creation, AT_address)"); // AT state on a per-block basis - 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)"); + stmt.execute("CREATE TABLE ATStates (AT_address QoraAddress, height INTEGER NOT NULL, creation TIMESTAMP WITH TIME ZONE, " + + "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)"); + // For finding per-block AT states, ordered by creation timestamp + stmt.execute("CREATE INDEX BlockATStateIndex on ATStates (height, creation, AT_address)"); // Generated AT Transactions stmt.execute( - "CREATE TABLE ATTransactions (signature Signature, sender QoraPublicKey NOT NULL, recipient QoraAddress, amount QoraAmount, asset_id AssetID, message ATMessage, " + "CREATE TABLE ATTransactions (signature Signature, AT_address QoraAddress 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 index 279c540a..f1103985 100644 --- a/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java +++ b/src/repository/hsqldb/transaction/HSQLDBATTransactionRepository.java @@ -17,12 +17,12 @@ public class HSQLDBATTransactionRepository extends HSQLDBTransactionRepository { } 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)) { + try (ResultSet resultSet = this.repository + .checkedExecute("SELECT AT_address, recipient, amount, asset_id, message FROM ATTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - byte[] senderPublicKey = resultSet.getBytes(1); + String atAddress = resultSet.getString(1); String recipient = resultSet.getString(2); BigDecimal amount = resultSet.getBigDecimal(3); @@ -37,7 +37,7 @@ public class HSQLDBATTransactionRepository extends HSQLDBTransactionRepository { if (resultSet.wasNull()) message = null; - return new ATTransactionData(senderPublicKey, recipient, amount, assetId, message, fee, timestamp, reference, signature); + return new ATTransactionData(atAddress, recipient, amount, assetId, message, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch AT transaction from repository", e); } @@ -49,7 +49,7 @@ public class HSQLDBATTransactionRepository extends HSQLDBTransactionRepository { HSQLDBSaver saveHelper = new HSQLDBSaver("ATTransactions"); - saveHelper.bind("signature", atTransactionData.getSignature()).bind("sender", atTransactionData.getSenderPublicKey()) + saveHelper.bind("signature", atTransactionData.getSignature()).bind("AT_address", atTransactionData.getATAddress()) .bind("recipient", atTransactionData.getRecipient()).bind("amount", atTransactionData.getAmount()) .bind("asset_id", atTransactionData.getAssetId()).bind("message", atTransactionData.getMessage()); diff --git a/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index 9a2ade4d..8360274a 100644 --- a/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -164,13 +164,22 @@ public class HSQLDBTransactionRepository implements TransactionRepository { } } + /** + * Returns payments associated with a transaction's signature. + *

+ * Used by various transaction types, like Payment, MultiPayment, ArbitraryTransaction. + * + * @param signature + * @return list of payments, empty if none found + * @throws DataException + */ protected List getPaymentsFromSignature(byte[] signature) throws DataException { + List payments = new ArrayList(); + try (ResultSet resultSet = this.repository.checkedExecute("SELECT recipient, amount, asset_id FROM SharedTransactionPayments WHERE signature = ?", signature)) { if (resultSet == null) - return null; - - List payments = new ArrayList(); + return payments; // NOTE: do-while because checkedExecute() above has already called rs.next() for us do { diff --git a/src/test/ATTests.java b/src/test/ATTests.java index 076bb927..9d5a3a8a 100644 --- a/src/test/ATTests.java +++ b/src/test/ATTests.java @@ -9,6 +9,7 @@ import org.junit.Test; import com.google.common.hash.HashCode; +import data.at.ATStateData; import data.block.BlockData; import data.block.BlockTransactionData; import data.transaction.DeployATTransactionData; @@ -70,13 +71,22 @@ public class ATTests extends Common { long blockTimestamp = 1439997158336L; BigDecimal generatingBalance = BigDecimal.valueOf(1440368826L).setScale(8); byte[] generatorPublicKey = Base58.decode("X4s833bbtghh7gejmaBMbWqD44HrUobw93ANUuaNhFc"); - byte[] atBytes = HashCode.fromString("17950a6c62d17ff0caa545651c054a105f1c464daca443df846cc6a3d58f764b78c09cff50f0fd9ec2").asBytes(); + int atCount = 1; BigDecimal atFees = BigDecimal.valueOf(50.0).setScale(8); BlockData blockData = new BlockData(version, blockReference, transactionCount, totalFees, transactionsSignature, height, blockTimestamp, - generatingBalance, generatorPublicKey, generatorSignature, atBytes, atFees); + generatingBalance, generatorPublicKey, generatorSignature, atCount, atFees); repository.getBlockRepository().save(blockData); + + byte[] atBytes = HashCode.fromString("17950a6c62d17ff0caa545651c054a105f1c464daca443df846cc6a3d58f764b78c09cff50f0fd9ec2").asBytes(); + + String atAddress = Base58.encode(Arrays.copyOfRange(atBytes, 0, 25)); + byte[] stateHash = Arrays.copyOfRange(atBytes, 25, atBytes.length); + + ATStateData atStateData = new ATStateData(atAddress, height, timestamp, new byte[0], stateHash, atFees); + + repository.getATRepository().save(atStateData); } int sequence = 0; diff --git a/src/test/NavigationTests.java b/src/test/NavigationTests.java index 42cfdcb6..4ebdbc24 100644 --- a/src/test/NavigationTests.java +++ b/src/test/NavigationTests.java @@ -37,7 +37,7 @@ public class NavigationTests extends Common { System.out.println("Block " + blockData.getHeight() + ", signature: " + Base58.encode(blockData.getSignature())); - assertEquals(49778, blockData.getHeight()); + assertEquals((Integer) 49778, blockData.getHeight()); } } diff --git a/src/test/SignatureTests.java b/src/test/SignatureTests.java index bffc7144..2aa3f963 100644 --- a/src/test/SignatureTests.java +++ b/src/test/SignatureTests.java @@ -48,11 +48,7 @@ public class SignatureTests extends Common { PrivateKeyAccount generator = new PrivateKeyAccount(repository, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }); - byte[] atBytes = null; - - BigDecimal atFees = null; - - Block block = new Block(repository, version, reference, timestamp, generatingBalance, generator, atBytes, atFees); + Block block = new Block(repository, version, reference, timestamp, generatingBalance, generator); block.sign(); assertTrue(block.isSignatureValid()); diff --git a/src/test/TransactionTests.java b/src/test/TransactionTests.java index f976c59f..df8a17da 100644 --- a/src/test/TransactionTests.java +++ b/src/test/TransactionTests.java @@ -172,7 +172,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, paymentTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(paymentTransactionData); block.sign(); @@ -233,7 +233,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, registerNameTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(registerNameTransactionData); block.sign(); @@ -289,7 +289,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, updateNameTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(updateNameTransactionData); block.sign(); @@ -334,7 +334,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, sellNameTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(sellNameTransactionData); block.sign(); @@ -385,7 +385,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, cancelSellNameTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(cancelSellNameTransactionData); block.sign(); @@ -432,7 +432,7 @@ public class TransactionTests { byte[] buyersReference = somePaymentTransaction.getTransactionData().getSignature(); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(somePaymentTransaction.getTransactionData()); block.sign(); @@ -451,7 +451,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, buyNameTransaction.isValid()); // Forge new block with transaction - block = new Block(repository, parentBlockData, generator, null, null); + block = new Block(repository, parentBlockData, generator); block.addTransaction(buyNameTransactionData); block.sign(); @@ -504,7 +504,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, createPollTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(createPollTransactionData); block.sign(); @@ -563,7 +563,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, voteOnPollTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(voteOnPollTransactionData); block.sign(); @@ -630,7 +630,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, issueAssetTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(issueAssetTransactionData); block.sign(); @@ -720,7 +720,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, transferAssetTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(transferAssetTransactionData); block.sign(); @@ -800,7 +800,7 @@ public class TransactionTests { byte[] buyersReference = somePaymentTransaction.getTransactionData().getSignature(); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(somePaymentTransaction.getTransactionData()); block.sign(); @@ -824,7 +824,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, createOrderTransaction.isValid()); // Forge new block with transaction - block = new Block(repository, parentBlockData, generator, null, null); + block = new Block(repository, parentBlockData, generator); block.addTransaction(createOrderTransactionData); block.sign(); @@ -905,7 +905,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, cancelOrderTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(cancelOrderTransactionData); block.sign(); @@ -980,7 +980,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, createOrderTransaction.isValid()); // Forge new block with transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(createOrderTransactionData); block.sign(); @@ -1089,7 +1089,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, multiPaymentTransaction.isValid()); // Forge new block with payment transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(multiPaymentTransactionData); block.sign(); @@ -1159,7 +1159,7 @@ public class TransactionTests { assertEquals(ValidationResult.OK, messageTransaction.isValid()); // Forge new block with message transaction - Block block = new Block(repository, parentBlockData, generator, null, null); + Block block = new Block(repository, parentBlockData, generator); block.addTransaction(messageTransactionData); block.sign(); diff --git a/src/transform/Transformer.java b/src/transform/Transformer.java index cd6b4328..ad9959f9 100644 --- a/src/transform/Transformer.java +++ b/src/transform/Transformer.java @@ -14,4 +14,7 @@ public abstract class Transformer { public static final int SIGNATURE_LENGTH = 64; public static final int TIMESTAMP_LENGTH = LONG_LENGTH; + public static final int MD5_LENGTH = 16; + public static final int SHA256_LENGTH = 32; + } diff --git a/src/transform/block/BlockTransformer.java b/src/transform/block/BlockTransformer.java index 7d7336ae..5bc5796e 100644 --- a/src/transform/block/BlockTransformer.java +++ b/src/transform/block/BlockTransformer.java @@ -17,6 +17,7 @@ import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import data.assets.TradeData; +import data.at.ATStateData; import data.block.BlockData; import data.transaction.TransactionData; import qora.account.PublicKeyAccount; @@ -24,12 +25,13 @@ import qora.assets.Order; import qora.block.Block; import qora.transaction.CreateOrderTransaction; import qora.transaction.Transaction; +import qora.transaction.Transaction.TransactionType; import repository.DataException; import transform.TransformationException; import transform.Transformer; import transform.transaction.TransactionTransformer; import utils.Base58; -import utils.Pair; +import utils.Triple; import utils.Serialization; public class BlockTransformer extends Transformer { @@ -52,6 +54,9 @@ public class BlockTransformer extends Transformer { protected static final int AT_FEES_LENGTH = LONG_LENGTH; protected static final int AT_LENGTH = AT_FEES_LENGTH + AT_BYTES_LENGTH; + protected static final int V2_AT_ENTRY_LENGTH = ADDRESS_LENGTH + MD5_LENGTH; + protected static final int V4_AT_ENTRY_LENGTH = ADDRESS_LENGTH + SHA256_LENGTH + BIG_DECIMAL_LENGTH; + /** * Extract block data and transaction data from serialized bytes. * @@ -59,7 +64,7 @@ public class BlockTransformer extends Transformer { * @return BlockData and a List of transactions. * @throws TransformationException */ - public static Pair> fromBytes(byte[] bytes) throws TransformationException { + public static Triple, List> fromBytes(byte[] bytes) throws TransformationException { if (bytes == null) return null; @@ -88,25 +93,74 @@ public class BlockTransformer extends Transformer { byte[] generatorSignature = new byte[GENERATOR_SIGNATURE_LENGTH]; byteBuffer.get(generatorSignature); - byte[] atBytes = null; - BigDecimal atFees = null; + BigDecimal totalFees = BigDecimal.ZERO.setScale(8); + + int atCount = 0; + BigDecimal atFees = BigDecimal.ZERO.setScale(8); + List atStates = new ArrayList(); + if (version >= 2) { int atBytesLength = byteBuffer.getInt(); if (atBytesLength > Block.MAX_BLOCK_BYTES) throw new TransformationException("Byte data too long for Block's AT info"); - atBytes = new byte[atBytesLength]; - byteBuffer.get(atBytes); + ByteBuffer atByteBuffer = byteBuffer.slice(); + atByteBuffer.limit(atBytesLength); - atFees = BigDecimal.valueOf(byteBuffer.getLong()).setScale(8); + if (version < 4) { + // For versions < 4, read AT-address & MD5 pairs + if (atBytesLength % V2_AT_ENTRY_LENGTH != 0) + throw new TransformationException("AT byte data not a multiple of version 2+ entries"); + + while (atByteBuffer.hasRemaining()) { + byte[] atAddressBytes = new byte[ADDRESS_LENGTH]; + atByteBuffer.get(atAddressBytes); + String atAddress = Base58.encode(atAddressBytes); + + byte[] stateHash = new byte[MD5_LENGTH]; + atByteBuffer.get(stateHash); + + atStates.add(new ATStateData(atAddress, stateHash)); + } + + // Bump byteBuffer over AT states just read in slice + byteBuffer.position(byteBuffer.position() + atBytesLength); + + // AT fees follow in versions < 4 + atFees = Serialization.deserializeBigDecimal(byteBuffer); + } else { + // For block versions >= 4, read AT-address, SHA256 hash and fees + if (atBytesLength % V4_AT_ENTRY_LENGTH != 0) + throw new TransformationException("AT byte data not a multiple of version 4+ entries"); + + while (atByteBuffer.hasRemaining()) { + byte[] atAddressBytes = new byte[ADDRESS_LENGTH]; + atByteBuffer.get(atAddressBytes); + String atAddress = Base58.encode(atAddressBytes); + + byte[] stateHash = new byte[SHA256_LENGTH]; + atByteBuffer.get(stateHash); + + BigDecimal fees = Serialization.deserializeBigDecimal(atByteBuffer); + // Add this AT's fees to our total + atFees = atFees.add(fees); + + atStates.add(new ATStateData(atAddress, stateHash, fees)); + } + } + + // AT count to reflect the number of states we have + atCount = atStates.size(); + + // Add AT fees to totalFees + totalFees = totalFees.add(atFees); } int transactionCount = byteBuffer.getInt(); // Parse transactions now, compared to deferred parsing in Gen1, so we can throw ParseException if need be. List transactions = new ArrayList(); - BigDecimal totalFees = BigDecimal.ZERO.setScale(8); for (int t = 0; t < transactionCount; ++t) { if (byteBuffer.remaining() < TRANSACTION_SIZE_LENGTH) @@ -126,26 +180,28 @@ public class BlockTransformer extends Transformer { TransactionData transactionData = TransactionTransformer.fromBytes(transactionBytes); transactions.add(transactionData); - totalFees.add(transactionData.getFee()); + totalFees = totalFees.add(transactionData.getFee()); } if (byteBuffer.hasRemaining()) throw new TransformationException("Excess byte data found after parsing Block"); - // XXX we don't know height! - int height = 0; + // We don't have a height! + Integer height = null; BlockData blockData = new BlockData(version, reference, transactionCount, totalFees, transactionsSignature, height, timestamp, generatingBalance, - generatorPublicKey, generatorSignature, atBytes, atFees); + generatorPublicKey, generatorSignature, atCount, atFees); - return new Pair>(blockData, transactions); + return new Triple, List>(blockData, transactions, atStates); } public static int getDataLength(Block block) throws TransformationException { BlockData blockData = block.getBlockData(); int blockLength = BASE_LENGTH; - if (blockData.getVersion() >= 2 && blockData.getAtBytes() != null) - blockLength += AT_FEES_LENGTH + AT_BYTES_LENGTH + blockData.getAtBytes().length; + if (blockData.getVersion() >= 4) + blockLength += AT_BYTES_LENGTH + blockData.getATCount() * V4_AT_ENTRY_LENGTH; + else if (blockData.getVersion() >= 2) + blockLength += AT_FEES_LENGTH + AT_BYTES_LENGTH + blockData.getATCount() * V2_AT_ENTRY_LENGTH; try { // Short cut for no transactions @@ -177,18 +233,29 @@ public class BlockTransformer extends Transformer { bytes.write(blockData.getTransactionsSignature()); bytes.write(blockData.getGeneratorSignature()); - if (blockData.getVersion() >= 2) { - byte[] atBytes = blockData.getAtBytes(); + if (blockData.getVersion() >= 4) { + int atBytesLength = blockData.getATCount() * V4_AT_ENTRY_LENGTH; + bytes.write(Ints.toByteArray(atBytesLength)); - if (atBytes != null) { - bytes.write(Ints.toByteArray(atBytes.length)); - bytes.write(atBytes); - // NOTE: atFees serialized as long value, not as BigDecimal, for historic compatibility - bytes.write(Longs.toByteArray(blockData.getAtFees().longValue())); - } else { - bytes.write(Ints.toByteArray(0)); - bytes.write(Longs.toByteArray(0L)); + for (ATStateData atStateData : block.getATStates()) { + bytes.write(Base58.decode(atStateData.getATAddress())); + bytes.write(atStateData.getStateHash()); + Serialization.serializeBigDecimal(bytes, atStateData.getFees()); } + } else if (blockData.getVersion() >= 2) { + int atBytesLength = blockData.getATCount() * V2_AT_ENTRY_LENGTH; + bytes.write(Ints.toByteArray(atBytesLength)); + + for (ATStateData atStateData : block.getATStates()) { + bytes.write(Base58.decode(atStateData.getATAddress())); + bytes.write(atStateData.getStateHash()); + } + + if (blockData.getATFees() != null) + // NOTE: atFees serialized as long value, not as BigDecimal, for historic compatibility + bytes.write(Longs.toByteArray(blockData.getATFees().longValue())); + else + bytes.write(Longs.toByteArray(0)); } // Transactions @@ -263,30 +330,39 @@ public class BlockTransformer extends Transformer { json.put("assetTrades", tradesHappened); // Add CIYAM AT info (if any) - if (blockData.getAtBytes() != null) { - json.put("blockATs", HashCode.fromBytes(blockData.getAtBytes()).toString()); - json.put("atFees", blockData.getAtFees()); + if (blockData.getATCount() > 0) { + JSONArray atsJson = new JSONArray(); + + try { + for (ATStateData atStateData : block.getATStates()) { + JSONObject atJson = new JSONObject(); + + atJson.put("AT", atStateData.getATAddress()); + atJson.put("stateHash", HashCode.fromBytes(atStateData.getStateHash()).toString()); + + if (blockData.getVersion() >= 4) + atJson.put("fees", atStateData.getFees().toPlainString()); + + atsJson.add(atJson); + } + } catch (DataException e) { + throw new TransformationException("Unable to transform block into JSON", e); + } + + json.put("ATs", atsJson); + + if (blockData.getVersion() >= 2) + json.put("atFees", blockData.getATFees()); } return json; } public static byte[] getBytesForGeneratorSignature(BlockData blockData) throws TransformationException { - try { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(GENERATOR_SIGNATURE_LENGTH + GENERATING_BALANCE_LENGTH + GENERATOR_LENGTH); + byte[] generatorSignature = Arrays.copyOf(blockData.getReference(), GENERATOR_SIGNATURE_LENGTH); + PublicKeyAccount generator = new PublicKeyAccount(null, blockData.getGeneratorPublicKey()); - // Only copy the generator signature from reference, which is the first 64 bytes. - bytes.write(Arrays.copyOf(blockData.getReference(), GENERATOR_SIGNATURE_LENGTH)); - - bytes.write(Longs.toByteArray(blockData.getGeneratingBalance().longValue())); - - // We're padding here just in case the generator is the genesis account whose public key is only 8 bytes long. - bytes.write(Bytes.ensureCapacity(blockData.getGeneratorPublicKey(), GENERATOR_LENGTH, 0)); - - return bytes.toByteArray(); - } catch (IOException e) { - throw new TransformationException(e); - } + return getBytesForGeneratorSignature(generatorSignature, blockData.getGeneratingBalance(), generator); } public static byte[] getBytesForGeneratorSignature(byte[] generatorSignature, BigDecimal generatingBalance, PublicKeyAccount generator) @@ -308,13 +384,18 @@ public class BlockTransformer extends Transformer { } public static byte[] getBytesForTransactionsSignature(Block block) throws TransformationException { - ByteArrayOutputStream bytes = new ByteArrayOutputStream( - GENERATOR_SIGNATURE_LENGTH + block.getBlockData().getTransactionCount() * TransactionTransformer.SIGNATURE_LENGTH); - try { + List transactions = block.getTransactions(); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(GENERATOR_SIGNATURE_LENGTH + transactions.size() * TransactionTransformer.SIGNATURE_LENGTH); + bytes.write(block.getBlockData().getGeneratorSignature()); - for (Transaction transaction : block.getTransactions()) { + for (Transaction transaction : transactions) { + // For legacy blocks, we don't include AT-Transactions + if (block.getBlockData().getVersion() < 4 && transaction.getTransactionData().getType() == TransactionType.AT) + continue; + if (!transaction.isSignatureValid()) throw new TransformationException("Transaction signature invalid when building block's transactions signature"); diff --git a/src/transform/transaction/ATTransactionTransformer.java b/src/transform/transaction/ATTransactionTransformer.java new file mode 100644 index 00000000..ff83272b --- /dev/null +++ b/src/transform/transaction/ATTransactionTransformer.java @@ -0,0 +1,92 @@ +package transform.transaction; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.json.simple.JSONObject; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; + +import data.transaction.TransactionData; +import data.transaction.ATTransactionData; +import transform.TransformationException; +import utils.Serialization; + +public class ATTransactionTransformer extends TransactionTransformer { + + // Property lengths + private static final int SENDER_LENGTH = ADDRESS_LENGTH; + private static final int RECIPIENT_LENGTH = ADDRESS_LENGTH; + private static final int AMOUNT_LENGTH = BIG_DECIMAL_LENGTH; + private static final int ASSET_ID_LENGTH = LONG_LENGTH; + private static final int DATA_SIZE_LENGTH = INT_LENGTH; + + private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + SENDER_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH + ASSET_ID_LENGTH + DATA_SIZE_LENGTH; + + static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { + throw new TransformationException("Serialized AT Transactions should not exist!"); + } + + public static int getDataLength(TransactionData transactionData) throws TransformationException { + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + return TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + atTransactionData.getMessage().length; + } + + public static byte[] toBytes(TransactionData transactionData) throws TransformationException { + try { + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + + bytes.write(Ints.toByteArray(atTransactionData.getType().value)); + bytes.write(Longs.toByteArray(atTransactionData.getTimestamp())); + bytes.write(atTransactionData.getReference()); + + Serialization.serializeAddress(bytes, atTransactionData.getATAddress()); + + Serialization.serializeAddress(bytes, atTransactionData.getRecipient()); + + if (atTransactionData.getAssetId() != null) { + Serialization.serializeBigDecimal(bytes, atTransactionData.getAmount()); + bytes.write(Longs.toByteArray(atTransactionData.getAssetId())); + } + + byte[] message = atTransactionData.getMessage(); + if (message.length > 0) { + bytes.write(Ints.toByteArray(message.length)); + bytes.write(message); + } else { + bytes.write(Ints.toByteArray(0)); + } + + Serialization.serializeBigDecimal(bytes, atTransactionData.getFee()); + + if (atTransactionData.getSignature() != null) + bytes.write(atTransactionData.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 { + ATTransactionData atTransactionData = (ATTransactionData) transactionData; + + json.put("sender", atTransactionData.getATAddress()); + + } catch (ClassCastException e) { + throw new TransformationException(e); + } + + return json; + } + +} diff --git a/src/utils/Pair.java b/src/utils/Pair.java index 8c353395..8468bbee 100644 --- a/src/utils/Pair.java +++ b/src/utils/Pair.java @@ -29,4 +29,22 @@ public class Pair { return b; } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + + if (!(o instanceof Pair)) + return false; + + Pair other = (Pair) o; + + return this.a.equals(other.getA()) && this.b.equals(other.getB()); + } + + @Override + public int hashCode() { + return this.a.hashCode() ^ this.b.hashCode(); + } + } diff --git a/src/utils/Triple.java b/src/utils/Triple.java new file mode 100644 index 00000000..c19ee068 --- /dev/null +++ b/src/utils/Triple.java @@ -0,0 +1,42 @@ +package utils; + +public class Triple { + + private T a; + private U b; + private V c; + + public Triple() { + } + + public Triple(T a, U b, V c) { + this.a = a; + this.b = b; + this.c = c; + } + + public void setA(T a) { + this.a = a; + } + + public T getA() { + return a; + } + + public void setB(U b) { + this.b = b; + } + + public U getB() { + return b; + } + + public void setC(V c) { + this.c = c; + } + + public V getC() { + return c; + } + +} diff --git a/src/v1feeder.java b/src/v1feeder.java index a2c13a30..ab032645 100644 --- a/src/v1feeder.java +++ b/src/v1feeder.java @@ -1,7 +1,9 @@ +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.OutputStream; +import java.math.BigDecimal; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; @@ -9,17 +11,32 @@ import java.net.SocketTimeoutException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; +import org.json.simple.parser.ParseException; +import com.google.common.hash.HashCode; +import com.google.common.primitives.Bytes; import com.google.common.primitives.Ints; +import data.at.ATData; +import data.at.ATStateData; import data.block.BlockData; +import data.transaction.ATTransactionData; import data.transaction.TransactionData; +import qora.assets.Asset; import qora.block.Block; import qora.block.Block.ValidationResult; import qora.block.BlockChain; @@ -29,7 +46,10 @@ import repository.Repository; import repository.RepositoryManager; import transform.TransformationException; import transform.block.BlockTransformer; +import transform.transaction.ATTransactionTransformer; +import utils.Base58; import utils.Pair; +import utils.Triple; public class v1feeder extends Thread { @@ -77,6 +97,9 @@ public class v1feeder extends Thread { private long lastPingTimestamp = System.currentTimeMillis(); private List signatures = new ArrayList(); + private static Map, BigDecimal> legacyATFees; + private static Map> legacyATTransactions; + private v1feeder(String address, int port) throws InterruptedException { try { for (int i = 0; i < 10; ++i) @@ -177,6 +200,9 @@ public class v1feeder extends Thread { // shove into list int numSignatures = byteBuffer.getInt(); + if (numSignatures == 0) + throw new RuntimeException("No signatures from peer - are we up to date?"); + while (numSignatures-- > 0) { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); @@ -201,7 +227,7 @@ public class v1feeder extends Thread { byte[] blockBytes = new byte[byteBuffer.remaining()]; byteBuffer.get(blockBytes); - Pair> blockInfo = null; + Triple, List> blockInfo = null; try { blockInfo = BlockTransformer.fromBytes(blockBytes); @@ -211,7 +237,26 @@ public class v1feeder extends Thread { } try (final Repository repository = RepositoryManager.getRepository()) { - Block block = new Block(repository, blockInfo.getA(), blockInfo.getB()); + BlockData blockData = blockInfo.getA(); + + // Adjust AT state data to include fees + List atStates = new ArrayList(); + for (ATStateData atState : blockInfo.getC()) { + BigDecimal fees = legacyATFees.get(new Pair(atState.getATAddress(), claimedHeight)); + ATData atData = repository.getATRepository().fromATAddress(atState.getATAddress()); + + atStates.add(new ATStateData(atState.getATAddress(), claimedHeight, atData.getCreation(), null, atState.getStateHash(), fees)); + } + + // AT-Transaction injection goes here! + List transactions = blockInfo.getB(); + List atTransactions = legacyATTransactions.get(claimedHeight); + if (atTransactions != null) { + transactions.addAll(0, atTransactions); + blockData.setTransactionCount(blockData.getTransactionCount() + atTransactions.size()); + } + + Block block = new Block(repository, blockData, transactions, atStates); if (!block.isSignatureValid()) { LOGGER.error("Invalid block signature"); @@ -398,12 +443,88 @@ public class v1feeder extends Thread { } } + private static void readLegacyATs(String legacyATPathname) { + legacyATFees = new HashMap, BigDecimal>(); + legacyATTransactions = new HashMap>(); + + Path path = Paths.get(legacyATPathname); + + JSONArray json = null; + + try (BufferedReader in = Files.newBufferedReader(path)) { + json = (JSONArray) JSONValue.parseWithException(in); + } catch (IOException | ParseException e) { + throw new RuntimeException("Couldn't read legacy AT JSON file"); + } + + for (Object o : json) { + JSONObject entry = (JSONObject) o; + + int height = Integer.parseInt((String) entry.get("height")); + long timestamp = (Long) entry.get("timestamp"); + + JSONArray transactionEntries = (JSONArray) entry.get("transactions"); + + List transactions = new ArrayList(); + + for (Object t : transactionEntries) { + JSONObject transactionEntry = (JSONObject) t; + + String recipient = (String) transactionEntry.get("recipient"); + String sender = (String) transactionEntry.get("sender"); + BigDecimal amount = new BigDecimal((String) transactionEntry.get("amount")).setScale(8); + + if (recipient.equals("1111111111111111111111111")) { + // fee + legacyATFees.put(new Pair(sender, height), amount); + } else { + // Actual AT Transaction + String messageString = (String) transactionEntry.get("message"); + byte[] message = messageString.isEmpty() ? new byte[0] : HashCode.fromString(messageString).asBytes(); + int sequence = ((Long) transactionEntry.get("seq")).intValue(); + byte[] reference = Base58.decode((String) transactionEntry.get("reference")); + + // reference is AT's deploy tx signature + // sender's public key is genesis account + // zero fee + // timestamp is block's timestamp + // signature = duplicated hash of transaction data + + BigDecimal fee = BigDecimal.ZERO.setScale(8); + + TransactionData transactionData = new ATTransactionData(sender, recipient, amount, Asset.QORA, message, fee, timestamp, reference); + byte[] digest; + try { + digest = Crypto.digest(ATTransactionTransformer.toBytes(transactionData)); + byte[] signature = Bytes.concat(digest, digest); + + transactionData = new ATTransactionData(sender, recipient, amount, Asset.QORA, message, fee, timestamp, reference, signature); + } catch (TransformationException e) { + throw new RuntimeException("Couldn't transform AT Transaction into bytes", e); + } + + if (sequence > transactions.size()) + transactions.add(transactionData); + else + transactions.add(sequence, transactionData); + } + } + + if (!transactions.isEmpty()) + legacyATTransactions.put(height, transactions); + } + } + public static void main(String[] args) { - if (args.length == 0) { - System.err.println("usage: v1feeder v1-node-address [port]"); + if (args.length < 2 || args.length > 3) { + System.err.println("usage: v1feeder legacy-AT-json v1-node-address [port]"); + System.err.println("example: v1feeder legacy-ATs.json 10.0.0.100 9084"); System.exit(1); } + String legacyATPathname = args[0]; + readLegacyATs(legacyATPathname); + try { test.Common.setRepository(); } catch (DataException e) { @@ -419,8 +540,8 @@ public class v1feeder extends Thread { } // connect to v1 node - String address = args[0]; - int port = args.length > 1 ? Integer.valueOf(args[1]) : DEFAULT_PORT; + String address = args[1]; + int port = args.length > 2 ? Integer.valueOf(args[2]) : DEFAULT_PORT; try { new v1feeder(address, port).join();