mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-11 17:55:50 +00:00
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!
This commit is contained in:
parent
e9d8b3e6e3
commit
46eee3cbce
Binary file not shown.
@ -1 +1 @@
|
||||
1d6f5d634a2c4e570a5a8af260a51653
|
||||
ab1560171ae5c6c15b0dfa8e6cccc7f8
|
@ -1 +1 @@
|
||||
c6387380bc5db1f0a98ecbb480b17bd89b564401
|
||||
c293c9656f43b432a08053f19ec5aa0de1cd10ea
|
12
lib/org/ciyam/at/maven-metadata-local.xml
Normal file
12
lib/org/ciyam/at/maven-metadata-local.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<groupId>org.ciyam</groupId>
|
||||
<artifactId>at</artifactId>
|
||||
<versioning>
|
||||
<release>1.0</release>
|
||||
<versions>
|
||||
<version>1.0</version>
|
||||
</versions>
|
||||
<lastUpdated>20181015085522</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
@ -7,6 +7,6 @@
|
||||
<versions>
|
||||
<version>1.0</version>
|
||||
</versions>
|
||||
<lastUpdated>20181003154752</lastUpdated>
|
||||
<lastUpdated>20181015081124</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
|
@ -1 +1 @@
|
||||
bc81bc1f9b74a4eececd5dd8b29e47d8
|
||||
2369bf36c52580a89d5ea71a0f037a82
|
@ -1 +1 @@
|
||||
feefde4343bda4d6e13159e5c01f8b4f8963a1bc
|
||||
6bc38899b93ffce2286ae26f7af0b2d8b69db3cf
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
128
src/qora/transaction/ATTransaction.java
Normal file
128
src/qora/transaction/ATTransaction.java
Normal file
@ -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<Account> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user