/******************************************************************************
* Copyright © 2013-2016 The Nxt Core Developers. *
* *
* See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* Nxt software, including this file, may be copied, modified, propagated, *
* or distributed except according to the terms contained in the LICENSE.txt *
* file. *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
package nxt;
import nxt.crypto.Crypto;
import nxt.crypto.EncryptedData;
import nxt.util.Convert;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public interface Attachment extends Appendix {
TransactionType getTransactionType();
abstract class AbstractAttachment extends Appendix.AbstractAppendix implements Attachment {
private AbstractAttachment(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
private AbstractAttachment(JSONObject attachmentData) {
super(attachmentData);
}
private AbstractAttachment(int version) {
super(version);
}
private AbstractAttachment() {}
@Override
final String getAppendixName() {
return getTransactionType().getName();
}
@Override
final void validate(Transaction transaction) throws NxtException.ValidationException {
getTransactionType().validateAttachment(transaction);
}
@Override
final void apply(Transaction transaction, Account senderAccount, Account recipientAccount) {
getTransactionType().apply((TransactionImpl) transaction, senderAccount, recipientAccount);
}
@Override
public final Fee getBaselineFee(Transaction transaction) {
return getTransactionType().getBaselineFee(transaction);
}
@Override
public final Fee getNextFee(Transaction transaction) {
return getTransactionType().getNextFee(transaction);
}
@Override
public final int getBaselineFeeHeight() {
return getTransactionType().getBaselineFeeHeight();
}
@Override
public final int getNextFeeHeight() {
return getTransactionType().getNextFeeHeight();
}
@Override
final boolean isPhasable() {
return !(this instanceof Prunable) && getTransactionType().isPhasable();
}
final int getFinishValidationHeight(Transaction transaction) {
return isPhased(transaction) ? transaction.getPhasing().getFinishHeight() - 1 : Nxt.getBlockchain().getHeight();
}
}
abstract class EmptyAttachment extends AbstractAttachment {
private EmptyAttachment() {
super(0);
}
@Override
final int getMySize() {
return 0;
}
@Override
final void putMyBytes(ByteBuffer buffer) {
}
@Override
final void putMyJSON(JSONObject json) {
}
@Override
final boolean verifyVersion(byte transactionVersion) {
return true;
}
}
EmptyAttachment ORDINARY_PAYMENT = new EmptyAttachment() {
@Override
public TransactionType getTransactionType() {
return TransactionType.Payment.ORDINARY;
}
};
// the message payload is in the Appendix
EmptyAttachment ARBITRARY_MESSAGE = new EmptyAttachment() {
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ARBITRARY_MESSAGE;
}
};
final class MessagingAliasAssignment extends AbstractAttachment {
private final String aliasName;
private final String aliasURI;
MessagingAliasAssignment(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
aliasName = Convert.readString(buffer, buffer.get(), Constants.MAX_ALIAS_LENGTH).trim();
aliasURI = Convert.readString(buffer, buffer.getShort(), Constants.MAX_ALIAS_URI_LENGTH).trim();
}
MessagingAliasAssignment(JSONObject attachmentData) {
super(attachmentData);
aliasName = Convert.nullToEmpty((String) attachmentData.get("alias")).trim();
aliasURI = Convert.nullToEmpty((String) attachmentData.get("uri")).trim();
}
public MessagingAliasAssignment(String aliasName, String aliasURI) {
this.aliasName = aliasName.trim();
this.aliasURI = aliasURI.trim();
}
@Override
int getMySize() {
return 1 + Convert.toBytes(aliasName).length + 2 + Convert.toBytes(aliasURI).length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] alias = Convert.toBytes(this.aliasName);
byte[] uri = Convert.toBytes(this.aliasURI);
buffer.put((byte)alias.length);
buffer.put(alias);
buffer.putShort((short) uri.length);
buffer.put(uri);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("alias", aliasName);
attachment.put("uri", aliasURI);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ALIAS_ASSIGNMENT;
}
public String getAliasName() {
return aliasName;
}
public String getAliasURI() {
return aliasURI;
}
}
final class MessagingAliasSell extends AbstractAttachment {
private final String aliasName;
private final long priceNQT;
MessagingAliasSell(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.aliasName = Convert.readString(buffer, buffer.get(), Constants.MAX_ALIAS_LENGTH);
this.priceNQT = buffer.getLong();
}
MessagingAliasSell(JSONObject attachmentData) {
super(attachmentData);
this.aliasName = Convert.nullToEmpty((String) attachmentData.get("alias"));
this.priceNQT = Convert.parseLong(attachmentData.get("priceNQT"));
}
public MessagingAliasSell(String aliasName, long priceNQT) {
this.aliasName = aliasName;
this.priceNQT = priceNQT;
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ALIAS_SELL;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(aliasName).length + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] aliasBytes = Convert.toBytes(aliasName);
buffer.put((byte)aliasBytes.length);
buffer.put(aliasBytes);
buffer.putLong(priceNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("alias", aliasName);
attachment.put("priceNQT", priceNQT);
}
public String getAliasName(){
return aliasName;
}
public long getPriceNQT(){
return priceNQT;
}
}
final class MessagingAliasBuy extends AbstractAttachment {
private final String aliasName;
MessagingAliasBuy(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.aliasName = Convert.readString(buffer, buffer.get(), Constants.MAX_ALIAS_LENGTH);
}
MessagingAliasBuy(JSONObject attachmentData) {
super(attachmentData);
this.aliasName = Convert.nullToEmpty((String) attachmentData.get("alias"));
}
public MessagingAliasBuy(String aliasName) {
this.aliasName = aliasName;
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ALIAS_BUY;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(aliasName).length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] aliasBytes = Convert.toBytes(aliasName);
buffer.put((byte) aliasBytes.length);
buffer.put(aliasBytes);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("alias", aliasName);
}
public String getAliasName(){
return aliasName;
}
}
final class MessagingAliasDelete extends AbstractAttachment {
private final String aliasName;
MessagingAliasDelete(final ByteBuffer buffer, final byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.aliasName = Convert.readString(buffer, buffer.get(), Constants.MAX_ALIAS_LENGTH);
}
MessagingAliasDelete(final JSONObject attachmentData) {
super(attachmentData);
this.aliasName = Convert.nullToEmpty((String) attachmentData.get("alias"));
}
public MessagingAliasDelete(final String aliasName) {
this.aliasName = aliasName;
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ALIAS_DELETE;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(aliasName).length;
}
@Override
void putMyBytes(final ByteBuffer buffer) {
byte[] aliasBytes = Convert.toBytes(aliasName);
buffer.put((byte)aliasBytes.length);
buffer.put(aliasBytes);
}
@Override
void putMyJSON(final JSONObject attachment) {
attachment.put("alias", aliasName);
}
public String getAliasName(){
return aliasName;
}
}
final class MessagingPollCreation extends AbstractAttachment {
public final static class PollBuilder {
private final String pollName;
private final String pollDescription;
private final String[] pollOptions;
private final int finishHeight;
private final byte votingModel;
private long minBalance = 0;
private byte minBalanceModel;
private final byte minNumberOfOptions;
private final byte maxNumberOfOptions;
private final byte minRangeValue;
private final byte maxRangeValue;
private long holdingId;
public PollBuilder(final String pollName, final String pollDescription, final String[] pollOptions,
final int finishHeight, final byte votingModel,
byte minNumberOfOptions, byte maxNumberOfOptions,
byte minRangeValue, byte maxRangeValue) {
this.pollName = pollName;
this.pollDescription = pollDescription;
this.pollOptions = pollOptions;
this.finishHeight = finishHeight;
this.votingModel = votingModel;
this.minNumberOfOptions = minNumberOfOptions;
this.maxNumberOfOptions = maxNumberOfOptions;
this.minRangeValue = minRangeValue;
this.maxRangeValue = maxRangeValue;
this.minBalanceModel = VoteWeighting.VotingModel.get(votingModel).getMinBalanceModel().getCode();
}
public PollBuilder minBalance(byte minBalanceModel, long minBalance) {
this.minBalanceModel = minBalanceModel;
this.minBalance = minBalance;
return this;
}
public PollBuilder holdingId(long holdingId) {
this.holdingId = holdingId;
return this;
}
public MessagingPollCreation build() {
return new MessagingPollCreation(this);
}
}
private final String pollName;
private final String pollDescription;
private final String[] pollOptions;
private final int finishHeight;
private final byte minNumberOfOptions;
private final byte maxNumberOfOptions;
private final byte minRangeValue;
private final byte maxRangeValue;
private final VoteWeighting voteWeighting;
MessagingPollCreation(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.pollName = Convert.readString(buffer, buffer.getShort(), Constants.MAX_POLL_NAME_LENGTH);
this.pollDescription = Convert.readString(buffer, buffer.getShort(), Constants.MAX_POLL_DESCRIPTION_LENGTH);
this.finishHeight = buffer.getInt();
int numberOfOptions = buffer.get();
if (numberOfOptions > Constants.MAX_POLL_OPTION_COUNT) {
throw new NxtException.NotValidException("Invalid number of poll options: " + numberOfOptions);
}
this.pollOptions = new String[numberOfOptions];
for (int i = 0; i < numberOfOptions; i++) {
this.pollOptions[i] = Convert.readString(buffer, buffer.getShort(), Constants.MAX_POLL_OPTION_LENGTH);
}
byte votingModel = buffer.get();
this.minNumberOfOptions = buffer.get();
this.maxNumberOfOptions = buffer.get();
this.minRangeValue = buffer.get();
this.maxRangeValue = buffer.get();
long minBalance = buffer.getLong();
byte minBalanceModel = buffer.get();
long holdingId = buffer.getLong();
this.voteWeighting = new VoteWeighting(votingModel, holdingId, minBalance, minBalanceModel);
}
MessagingPollCreation(JSONObject attachmentData) {
super(attachmentData);
this.pollName = ((String) attachmentData.get("name")).trim();
this.pollDescription = ((String) attachmentData.get("description")).trim();
this.finishHeight = ((Long) attachmentData.get("finishHeight")).intValue();
JSONArray options = (JSONArray) attachmentData.get("options");
this.pollOptions = new String[options.size()];
for (int i = 0; i < pollOptions.length; i++) {
this.pollOptions[i] = ((String) options.get(i)).trim();
}
byte votingModel = ((Long) attachmentData.get("votingModel")).byteValue();
this.minNumberOfOptions = ((Long) attachmentData.get("minNumberOfOptions")).byteValue();
this.maxNumberOfOptions = ((Long) attachmentData.get("maxNumberOfOptions")).byteValue();
this.minRangeValue = ((Long) attachmentData.get("minRangeValue")).byteValue();
this.maxRangeValue = ((Long) attachmentData.get("maxRangeValue")).byteValue();
long minBalance = Convert.parseLong(attachmentData.get("minBalance"));
byte minBalanceModel = ((Long) attachmentData.get("minBalanceModel")).byteValue();
long holdingId = Convert.parseUnsignedLong((String) attachmentData.get("holding"));
this.voteWeighting = new VoteWeighting(votingModel, holdingId, minBalance, minBalanceModel);
}
private MessagingPollCreation(PollBuilder builder) {
this.pollName = builder.pollName;
this.pollDescription = builder.pollDescription;
this.pollOptions = builder.pollOptions;
this.finishHeight = builder.finishHeight;
this.minNumberOfOptions = builder.minNumberOfOptions;
this.maxNumberOfOptions = builder.maxNumberOfOptions;
this.minRangeValue = builder.minRangeValue;
this.maxRangeValue = builder.maxRangeValue;
this.voteWeighting = new VoteWeighting(builder.votingModel, builder.holdingId, builder.minBalance, builder.minBalanceModel);
}
@Override
int getMySize() {
int size = 2 + Convert.toBytes(pollName).length + 2 + Convert.toBytes(pollDescription).length + 1;
for (String pollOption : pollOptions) {
size += 2 + Convert.toBytes(pollOption).length;
}
size += 4 + 1 + 1 + 1 + 1 + 1 + 8 + 1 + 8;
return size;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] name = Convert.toBytes(this.pollName);
byte[] description = Convert.toBytes(this.pollDescription);
byte[][] options = new byte[this.pollOptions.length][];
for (int i = 0; i < this.pollOptions.length; i++) {
options[i] = Convert.toBytes(this.pollOptions[i]);
}
buffer.putShort((short) name.length);
buffer.put(name);
buffer.putShort((short) description.length);
buffer.put(description);
buffer.putInt(finishHeight);
buffer.put((byte) options.length);
for (byte[] option : options) {
buffer.putShort((short) option.length);
buffer.put(option);
}
buffer.put(this.voteWeighting.getVotingModel().getCode());
buffer.put(this.minNumberOfOptions);
buffer.put(this.maxNumberOfOptions);
buffer.put(this.minRangeValue);
buffer.put(this.maxRangeValue);
buffer.putLong(this.voteWeighting.getMinBalance());
buffer.put(this.voteWeighting.getMinBalanceModel().getCode());
buffer.putLong(this.voteWeighting.getHoldingId());
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("name", this.pollName);
attachment.put("description", this.pollDescription);
attachment.put("finishHeight", this.finishHeight);
JSONArray options = new JSONArray();
if (this.pollOptions != null) {
Collections.addAll(options, this.pollOptions);
}
attachment.put("options", options);
attachment.put("minNumberOfOptions", this.minNumberOfOptions);
attachment.put("maxNumberOfOptions", this.maxNumberOfOptions);
attachment.put("minRangeValue", this.minRangeValue);
attachment.put("maxRangeValue", this.maxRangeValue);
attachment.put("votingModel", this.voteWeighting.getVotingModel().getCode());
attachment.put("minBalance", this.voteWeighting.getMinBalance());
attachment.put("minBalanceModel", this.voteWeighting.getMinBalanceModel().getCode());
attachment.put("holding", Long.toUnsignedString(this.voteWeighting.getHoldingId()));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.POLL_CREATION;
}
public String getPollName() {
return pollName;
}
public String getPollDescription() {
return pollDescription;
}
public int getFinishHeight() {
return finishHeight;
}
public String[] getPollOptions() {
return pollOptions;
}
public byte getMinNumberOfOptions() {
return minNumberOfOptions;
}
public byte getMaxNumberOfOptions() {
return maxNumberOfOptions;
}
public byte getMinRangeValue() {
return minRangeValue;
}
public byte getMaxRangeValue() {
return maxRangeValue;
}
public VoteWeighting getVoteWeighting() {
return voteWeighting;
}
}
final class MessagingVoteCasting extends AbstractAttachment {
private final long pollId;
private final byte[] pollVote;
public MessagingVoteCasting(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
pollId = buffer.getLong();
int numberOfOptions = buffer.get();
if (numberOfOptions > Constants.MAX_POLL_OPTION_COUNT) {
throw new NxtException.NotValidException("More than " + Constants.MAX_POLL_OPTION_COUNT + " options in a vote");
}
pollVote = new byte[numberOfOptions];
buffer.get(pollVote);
}
public MessagingVoteCasting(JSONObject attachmentData) {
super(attachmentData);
pollId = Convert.parseUnsignedLong((String) attachmentData.get("poll"));
JSONArray vote = (JSONArray) attachmentData.get("vote");
pollVote = new byte[vote.size()];
for (int i = 0; i < pollVote.length; i++) {
pollVote[i] = ((Long) vote.get(i)).byteValue();
}
}
public MessagingVoteCasting(long pollId, byte[] pollVote) {
this.pollId = pollId;
this.pollVote = pollVote;
}
@Override
int getMySize() {
return 8 + 1 + this.pollVote.length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(this.pollId);
buffer.put((byte) this.pollVote.length);
buffer.put(this.pollVote);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("poll", Long.toUnsignedString(this.pollId));
JSONArray vote = new JSONArray();
if (this.pollVote != null) {
for (byte aPollVote : this.pollVote) {
vote.add(aPollVote);
}
}
attachment.put("vote", vote);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.VOTE_CASTING;
}
public long getPollId() {
return pollId;
}
public byte[] getPollVote() {
return pollVote;
}
}
final class MessagingPhasingVoteCasting extends AbstractAttachment {
private final List<byte[]> transactionFullHashes;
private final byte[] revealedSecret;
MessagingPhasingVoteCasting(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
byte length = buffer.get();
transactionFullHashes = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
byte[] hash = new byte[32];
buffer.get(hash);
transactionFullHashes.add(hash);
}
int secretLength = buffer.getInt();
if (secretLength > Constants.MAX_PHASING_REVEALED_SECRET_LENGTH) {
throw new NxtException.NotValidException("Invalid revealed secret length " + secretLength);
}
if (secretLength > 0) {
revealedSecret = new byte[secretLength];
buffer.get(revealedSecret);
} else {
revealedSecret = Convert.EMPTY_BYTE;
}
}
MessagingPhasingVoteCasting(JSONObject attachmentData) {
super(attachmentData);
JSONArray hashes = (JSONArray) attachmentData.get("transactionFullHashes");
transactionFullHashes = new ArrayList<>(hashes.size());
hashes.forEach(hash -> transactionFullHashes.add(Convert.parseHexString((String) hash)));
String revealedSecret = Convert.emptyToNull((String) attachmentData.get("revealedSecret"));
this.revealedSecret = revealedSecret != null ? Convert.parseHexString(revealedSecret) : Convert.EMPTY_BYTE;
}
public MessagingPhasingVoteCasting(List<byte[]> transactionFullHashes, byte[] revealedSecret) {
this.transactionFullHashes = transactionFullHashes;
this.revealedSecret = revealedSecret;
}
@Override
int getMySize() {
return 1 + 32 * transactionFullHashes.size() + 4 + revealedSecret.length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.put((byte) transactionFullHashes.size());
transactionFullHashes.forEach(buffer::put);
buffer.putInt(revealedSecret.length);
buffer.put(revealedSecret);
}
@Override
void putMyJSON(JSONObject attachment) {
JSONArray jsonArray = new JSONArray();
transactionFullHashes.forEach(hash -> jsonArray.add(Convert.toHexString(hash)));
attachment.put("transactionFullHashes", jsonArray);
if (revealedSecret.length > 0) {
attachment.put("revealedSecret", Convert.toHexString(revealedSecret));
}
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.PHASING_VOTE_CASTING;
}
public List<byte[]> getTransactionFullHashes() {
return transactionFullHashes;
}
public byte[] getRevealedSecret() {
return revealedSecret;
}
}
final class MessagingHubAnnouncement extends AbstractAttachment {
private final long minFeePerByteNQT;
private final String[] uris;
MessagingHubAnnouncement(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.minFeePerByteNQT = buffer.getLong();
int numberOfUris = buffer.get();
if (numberOfUris > Constants.MAX_HUB_ANNOUNCEMENT_URIS) {
throw new NxtException.NotValidException("Invalid number of URIs: " + numberOfUris);
}
this.uris = new String[numberOfUris];
for (int i = 0; i < uris.length; i++) {
uris[i] = Convert.readString(buffer, buffer.getShort(), Constants.MAX_HUB_ANNOUNCEMENT_URI_LENGTH);
}
}
MessagingHubAnnouncement(JSONObject attachmentData) throws NxtException.NotValidException {
super(attachmentData);
this.minFeePerByteNQT = (Long) attachmentData.get("minFeePerByte");
try {
JSONArray urisData = (JSONArray) attachmentData.get("uris");
this.uris = new String[urisData.size()];
for (int i = 0; i < uris.length; i++) {
uris[i] = (String) urisData.get(i);
}
} catch (RuntimeException e) {
throw new NxtException.NotValidException("Error parsing hub terminal announcement parameters", e);
}
}
public MessagingHubAnnouncement(long minFeePerByteNQT, String[] uris) {
this.minFeePerByteNQT = minFeePerByteNQT;
this.uris = uris;
}
@Override
int getMySize() {
int size = 8 + 1;
for (String uri : uris) {
size += 2 + Convert.toBytes(uri).length;
}
return size;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(minFeePerByteNQT);
buffer.put((byte) uris.length);
for (String uri : uris) {
byte[] uriBytes = Convert.toBytes(uri);
buffer.putShort((short)uriBytes.length);
buffer.put(uriBytes);
}
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("minFeePerByteNQT", minFeePerByteNQT);
JSONArray uris = new JSONArray();
Collections.addAll(uris, this.uris);
attachment.put("uris", uris);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.HUB_ANNOUNCEMENT;
}
public long getMinFeePerByteNQT() {
return minFeePerByteNQT;
}
public String[] getUris() {
return uris;
}
}
final class MessagingAccountInfo extends AbstractAttachment {
private final String name;
private final String description;
MessagingAccountInfo(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.name = Convert.readString(buffer, buffer.get(), Constants.MAX_ACCOUNT_NAME_LENGTH);
this.description = Convert.readString(buffer, buffer.getShort(), Constants.MAX_ACCOUNT_DESCRIPTION_LENGTH);
}
MessagingAccountInfo(JSONObject attachmentData) {
super(attachmentData);
this.name = Convert.nullToEmpty((String) attachmentData.get("name"));
this.description = Convert.nullToEmpty((String) attachmentData.get("description"));
}
public MessagingAccountInfo(String name, String description) {
this.name = name;
this.description = description;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(name).length + 2 + Convert.toBytes(description).length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] name = Convert.toBytes(this.name);
byte[] description = Convert.toBytes(this.description);
buffer.put((byte)name.length);
buffer.put(name);
buffer.putShort((short) description.length);
buffer.put(description);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("name", name);
attachment.put("description", description);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ACCOUNT_INFO;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
}
final class MessagingAccountProperty extends AbstractAttachment {
private final String property;
private final String value;
MessagingAccountProperty(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.property = Convert.readString(buffer, buffer.get(), Constants.MAX_ACCOUNT_PROPERTY_NAME_LENGTH).trim();
this.value = Convert.readString(buffer, buffer.get(), Constants.MAX_ACCOUNT_PROPERTY_VALUE_LENGTH).trim();
}
MessagingAccountProperty(JSONObject attachmentData) {
super(attachmentData);
this.property = Convert.nullToEmpty((String) attachmentData.get("property")).trim();
this.value = Convert.nullToEmpty((String) attachmentData.get("value")).trim();
}
public MessagingAccountProperty(String property, String value) {
this.property = property.trim();
this.value = Convert.nullToEmpty(value).trim();
}
@Override
int getMySize() {
return 1 + Convert.toBytes(property).length + 1 + Convert.toBytes(value).length;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] property = Convert.toBytes(this.property);
byte[] value = Convert.toBytes(this.value);
buffer.put((byte)property.length);
buffer.put(property);
buffer.put((byte)value.length);
buffer.put(value);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("property", property);
attachment.put("value", value);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ACCOUNT_PROPERTY;
}
public String getProperty() {
return property;
}
public String getValue() {
return value;
}
}
final class MessagingAccountPropertyDelete extends AbstractAttachment {
private final long propertyId;
MessagingAccountPropertyDelete(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.propertyId = buffer.getLong();
}
MessagingAccountPropertyDelete(JSONObject attachmentData) {
super(attachmentData);
this.propertyId = Convert.parseUnsignedLong((String)attachmentData.get("property"));
}
public MessagingAccountPropertyDelete(long propertyId) {
this.propertyId = propertyId;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(propertyId);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("property", Long.toUnsignedString(propertyId));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Messaging.ACCOUNT_PROPERTY_DELETE;
}
public long getPropertyId() {
return propertyId;
}
}
final class ColoredCoinsAssetIssuance extends AbstractAttachment {
private final String name;
private final String description;
private final long quantityQNT;
private final byte decimals;
ColoredCoinsAssetIssuance(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.name = Convert.readString(buffer, buffer.get(), Constants.MAX_ASSET_NAME_LENGTH);
this.description = Convert.readString(buffer, buffer.getShort(), Constants.MAX_ASSET_DESCRIPTION_LENGTH);
this.quantityQNT = buffer.getLong();
this.decimals = buffer.get();
}
ColoredCoinsAssetIssuance(JSONObject attachmentData) {
super(attachmentData);
this.name = (String) attachmentData.get("name");
this.description = Convert.nullToEmpty((String) attachmentData.get("description"));
this.quantityQNT = Convert.parseLong(attachmentData.get("quantityQNT"));
this.decimals = ((Long) attachmentData.get("decimals")).byteValue();
}
public ColoredCoinsAssetIssuance(String name, String description, long quantityQNT, byte decimals) {
this.name = name;
this.description = Convert.nullToEmpty(description);
this.quantityQNT = quantityQNT;
this.decimals = decimals;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(name).length + 2 + Convert.toBytes(description).length + 8 + 1;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] name = Convert.toBytes(this.name);
byte[] description = Convert.toBytes(this.description);
buffer.put((byte)name.length);
buffer.put(name);
buffer.putShort((short) description.length);
buffer.put(description);
buffer.putLong(quantityQNT);
buffer.put(decimals);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("name", name);
attachment.put("description", description);
attachment.put("quantityQNT", quantityQNT);
attachment.put("decimals", decimals);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.ASSET_ISSUANCE;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public long getQuantityQNT() {
return quantityQNT;
}
public byte getDecimals() {
return decimals;
}
}
final class ColoredCoinsAssetTransfer extends AbstractAttachment {
private final long assetId;
private final long quantityQNT;
private final String comment;
ColoredCoinsAssetTransfer(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.assetId = buffer.getLong();
this.quantityQNT = buffer.getLong();
this.comment = getVersion() == 0 ? Convert.readString(buffer, buffer.getShort(), Constants.MAX_ASSET_TRANSFER_COMMENT_LENGTH) : null;
}
ColoredCoinsAssetTransfer(JSONObject attachmentData) {
super(attachmentData);
this.assetId = Convert.parseUnsignedLong((String) attachmentData.get("asset"));
this.quantityQNT = Convert.parseLong(attachmentData.get("quantityQNT"));
this.comment = getVersion() == 0 ? Convert.nullToEmpty((String) attachmentData.get("comment")) : null;
}
public ColoredCoinsAssetTransfer(long assetId, long quantityQNT) {
this.assetId = assetId;
this.quantityQNT = quantityQNT;
this.comment = null;
}
@Override
int getMySize() {
return 8 + 8 + (getVersion() == 0 ? (2 + Convert.toBytes(comment).length) : 0);
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(assetId);
buffer.putLong(quantityQNT);
if (getVersion() == 0 && comment != null) {
byte[] commentBytes = Convert.toBytes(this.comment);
buffer.putShort((short) commentBytes.length);
buffer.put(commentBytes);
}
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("asset", Long.toUnsignedString(assetId));
attachment.put("quantityQNT", quantityQNT);
if (getVersion() == 0) {
attachment.put("comment", comment);
}
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.ASSET_TRANSFER;
}
public long getAssetId() {
return assetId;
}
public long getQuantityQNT() {
return quantityQNT;
}
public String getComment() {
return comment;
}
}
final class ColoredCoinsAssetDelete extends AbstractAttachment {
private final long assetId;
private final long quantityQNT;
ColoredCoinsAssetDelete(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.assetId = buffer.getLong();
this.quantityQNT = buffer.getLong();
}
ColoredCoinsAssetDelete(JSONObject attachmentData) {
super(attachmentData);
this.assetId = Convert.parseUnsignedLong((String)attachmentData.get("asset"));
this.quantityQNT = Convert.parseLong(attachmentData.get("quantityQNT"));
}
public ColoredCoinsAssetDelete(long assetId, long quantityQNT) {
this.assetId = assetId;
this.quantityQNT = quantityQNT;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(assetId);
buffer.putLong(quantityQNT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("asset", Long.toUnsignedString(assetId));
attachment.put("quantityQNT", quantityQNT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.ASSET_DELETE;
}
public long getAssetId() {
return assetId;
}
public long getQuantityQNT() {
return quantityQNT;
}
}
abstract class ColoredCoinsOrderPlacement extends AbstractAttachment {
private final long assetId;
private final long quantityQNT;
private final long priceNQT;
private ColoredCoinsOrderPlacement(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.assetId = buffer.getLong();
this.quantityQNT = buffer.getLong();
this.priceNQT = buffer.getLong();
}
private ColoredCoinsOrderPlacement(JSONObject attachmentData) {
super(attachmentData);
this.assetId = Convert.parseUnsignedLong((String) attachmentData.get("asset"));
this.quantityQNT = Convert.parseLong(attachmentData.get("quantityQNT"));
this.priceNQT = Convert.parseLong(attachmentData.get("priceNQT"));
}
private ColoredCoinsOrderPlacement(long assetId, long quantityQNT, long priceNQT) {
this.assetId = assetId;
this.quantityQNT = quantityQNT;
this.priceNQT = priceNQT;
}
@Override
int getMySize() {
return 8 + 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(assetId);
buffer.putLong(quantityQNT);
buffer.putLong(priceNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("asset", Long.toUnsignedString(assetId));
attachment.put("quantityQNT", quantityQNT);
attachment.put("priceNQT", priceNQT);
}
public long getAssetId() {
return assetId;
}
public long getQuantityQNT() {
return quantityQNT;
}
public long getPriceNQT() {
return priceNQT;
}
}
final class ColoredCoinsAskOrderPlacement extends ColoredCoinsOrderPlacement {
ColoredCoinsAskOrderPlacement(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
ColoredCoinsAskOrderPlacement(JSONObject attachmentData) {
super(attachmentData);
}
public ColoredCoinsAskOrderPlacement(long assetId, long quantityQNT, long priceNQT) {
super(assetId, quantityQNT, priceNQT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.ASK_ORDER_PLACEMENT;
}
}
final class ColoredCoinsBidOrderPlacement extends ColoredCoinsOrderPlacement {
ColoredCoinsBidOrderPlacement(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
ColoredCoinsBidOrderPlacement(JSONObject attachmentData) {
super(attachmentData);
}
public ColoredCoinsBidOrderPlacement(long assetId, long quantityQNT, long priceNQT) {
super(assetId, quantityQNT, priceNQT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.BID_ORDER_PLACEMENT;
}
}
abstract class ColoredCoinsOrderCancellation extends AbstractAttachment {
private final long orderId;
private ColoredCoinsOrderCancellation(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.orderId = buffer.getLong();
}
private ColoredCoinsOrderCancellation(JSONObject attachmentData) {
super(attachmentData);
this.orderId = Convert.parseUnsignedLong((String) attachmentData.get("order"));
}
private ColoredCoinsOrderCancellation(long orderId) {
this.orderId = orderId;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(orderId);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("order", Long.toUnsignedString(orderId));
}
public long getOrderId() {
return orderId;
}
}
final class ColoredCoinsAskOrderCancellation extends ColoredCoinsOrderCancellation {
ColoredCoinsAskOrderCancellation(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
ColoredCoinsAskOrderCancellation(JSONObject attachmentData) {
super(attachmentData);
}
public ColoredCoinsAskOrderCancellation(long orderId) {
super(orderId);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.ASK_ORDER_CANCELLATION;
}
}
final class ColoredCoinsBidOrderCancellation extends ColoredCoinsOrderCancellation {
ColoredCoinsBidOrderCancellation(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
ColoredCoinsBidOrderCancellation(JSONObject attachmentData) {
super(attachmentData);
}
public ColoredCoinsBidOrderCancellation(long orderId) {
super(orderId);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.BID_ORDER_CANCELLATION;
}
}
final class ColoredCoinsDividendPayment extends AbstractAttachment {
private final long assetId;
private final int height;
private final long amountNQTPerQNT;
ColoredCoinsDividendPayment(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.assetId = buffer.getLong();
this.height = buffer.getInt();
this.amountNQTPerQNT = buffer.getLong();
}
ColoredCoinsDividendPayment(JSONObject attachmentData) {
super(attachmentData);
this.assetId = Convert.parseUnsignedLong((String)attachmentData.get("asset"));
this.height = ((Long)attachmentData.get("height")).intValue();
this.amountNQTPerQNT = Convert.parseLong(attachmentData.get("amountNQTPerQNT"));
}
public ColoredCoinsDividendPayment(long assetId, int height, long amountNQTPerQNT) {
this.assetId = assetId;
this.height = height;
this.amountNQTPerQNT = amountNQTPerQNT;
}
@Override
int getMySize() {
return 8 + 4 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(assetId);
buffer.putInt(height);
buffer.putLong(amountNQTPerQNT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("asset", Long.toUnsignedString(assetId));
attachment.put("height", height);
attachment.put("amountNQTPerQNT", amountNQTPerQNT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.ColoredCoins.DIVIDEND_PAYMENT;
}
public long getAssetId() {
return assetId;
}
public int getHeight() {
return height;
}
public long getAmountNQTPerQNT() {
return amountNQTPerQNT;
}
}
final class DigitalGoodsListing extends AbstractAttachment {
private final String name;
private final String description;
private final String tags;
private final int quantity;
private final long priceNQT;
DigitalGoodsListing(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.name = Convert.readString(buffer, buffer.getShort(), Constants.MAX_DGS_LISTING_NAME_LENGTH);
this.description = Convert.readString(buffer, buffer.getShort(), Constants.MAX_DGS_LISTING_DESCRIPTION_LENGTH);
this.tags = Convert.readString(buffer, buffer.getShort(), Constants.MAX_DGS_LISTING_TAGS_LENGTH);
this.quantity = buffer.getInt();
this.priceNQT = buffer.getLong();
}
DigitalGoodsListing(JSONObject attachmentData) {
super(attachmentData);
this.name = (String) attachmentData.get("name");
this.description = (String) attachmentData.get("description");
this.tags = (String) attachmentData.get("tags");
this.quantity = ((Long) attachmentData.get("quantity")).intValue();
this.priceNQT = Convert.parseLong(attachmentData.get("priceNQT"));
}
public DigitalGoodsListing(String name, String description, String tags, int quantity, long priceNQT) {
this.name = name;
this.description = description;
this.tags = tags;
this.quantity = quantity;
this.priceNQT = priceNQT;
}
@Override
int getMySize() {
return 2 + Convert.toBytes(name).length + 2 + Convert.toBytes(description).length + 2
+ Convert.toBytes(tags).length + 4 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] nameBytes = Convert.toBytes(name);
buffer.putShort((short) nameBytes.length);
buffer.put(nameBytes);
byte[] descriptionBytes = Convert.toBytes(description);
buffer.putShort((short) descriptionBytes.length);
buffer.put(descriptionBytes);
byte[] tagsBytes = Convert.toBytes(tags);
buffer.putShort((short) tagsBytes.length);
buffer.put(tagsBytes);
buffer.putInt(quantity);
buffer.putLong(priceNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("name", name);
attachment.put("description", description);
attachment.put("tags", tags);
attachment.put("quantity", quantity);
attachment.put("priceNQT", priceNQT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.LISTING;
}
public String getName() { return name; }
public String getDescription() { return description; }
public String getTags() { return tags; }
public int getQuantity() { return quantity; }
public long getPriceNQT() { return priceNQT; }
}
final class DigitalGoodsDelisting extends AbstractAttachment {
private final long goodsId;
DigitalGoodsDelisting(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.goodsId = buffer.getLong();
}
DigitalGoodsDelisting(JSONObject attachmentData) {
super(attachmentData);
this.goodsId = Convert.parseUnsignedLong((String)attachmentData.get("goods"));
}
public DigitalGoodsDelisting(long goodsId) {
this.goodsId = goodsId;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(goodsId);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("goods", Long.toUnsignedString(goodsId));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.DELISTING;
}
public long getGoodsId() { return goodsId; }
}
final class DigitalGoodsPriceChange extends AbstractAttachment {
private final long goodsId;
private final long priceNQT;
DigitalGoodsPriceChange(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.goodsId = buffer.getLong();
this.priceNQT = buffer.getLong();
}
DigitalGoodsPriceChange(JSONObject attachmentData) {
super(attachmentData);
this.goodsId = Convert.parseUnsignedLong((String)attachmentData.get("goods"));
this.priceNQT = Convert.parseLong(attachmentData.get("priceNQT"));
}
public DigitalGoodsPriceChange(long goodsId, long priceNQT) {
this.goodsId = goodsId;
this.priceNQT = priceNQT;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(goodsId);
buffer.putLong(priceNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("goods", Long.toUnsignedString(goodsId));
attachment.put("priceNQT", priceNQT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.PRICE_CHANGE;
}
public long getGoodsId() { return goodsId; }
public long getPriceNQT() { return priceNQT; }
}
final class DigitalGoodsQuantityChange extends AbstractAttachment {
private final long goodsId;
private final int deltaQuantity;
DigitalGoodsQuantityChange(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.goodsId = buffer.getLong();
this.deltaQuantity = buffer.getInt();
}
DigitalGoodsQuantityChange(JSONObject attachmentData) {
super(attachmentData);
this.goodsId = Convert.parseUnsignedLong((String)attachmentData.get("goods"));
this.deltaQuantity = ((Long)attachmentData.get("deltaQuantity")).intValue();
}
public DigitalGoodsQuantityChange(long goodsId, int deltaQuantity) {
this.goodsId = goodsId;
this.deltaQuantity = deltaQuantity;
}
@Override
int getMySize() {
return 8 + 4;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(goodsId);
buffer.putInt(deltaQuantity);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("goods", Long.toUnsignedString(goodsId));
attachment.put("deltaQuantity", deltaQuantity);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.QUANTITY_CHANGE;
}
public long getGoodsId() { return goodsId; }
public int getDeltaQuantity() { return deltaQuantity; }
}
final class DigitalGoodsPurchase extends AbstractAttachment {
private final long goodsId;
private final int quantity;
private final long priceNQT;
private final int deliveryDeadlineTimestamp;
DigitalGoodsPurchase(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.goodsId = buffer.getLong();
this.quantity = buffer.getInt();
this.priceNQT = buffer.getLong();
this.deliveryDeadlineTimestamp = buffer.getInt();
}
DigitalGoodsPurchase(JSONObject attachmentData) {
super(attachmentData);
this.goodsId = Convert.parseUnsignedLong((String)attachmentData.get("goods"));
this.quantity = ((Long)attachmentData.get("quantity")).intValue();
this.priceNQT = Convert.parseLong(attachmentData.get("priceNQT"));
this.deliveryDeadlineTimestamp = ((Long)attachmentData.get("deliveryDeadlineTimestamp")).intValue();
}
public DigitalGoodsPurchase(long goodsId, int quantity, long priceNQT, int deliveryDeadlineTimestamp) {
this.goodsId = goodsId;
this.quantity = quantity;
this.priceNQT = priceNQT;
this.deliveryDeadlineTimestamp = deliveryDeadlineTimestamp;
}
@Override
int getMySize() {
return 8 + 4 + 8 + 4;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(goodsId);
buffer.putInt(quantity);
buffer.putLong(priceNQT);
buffer.putInt(deliveryDeadlineTimestamp);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("goods", Long.toUnsignedString(goodsId));
attachment.put("quantity", quantity);
attachment.put("priceNQT", priceNQT);
attachment.put("deliveryDeadlineTimestamp", deliveryDeadlineTimestamp);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.PURCHASE;
}
public long getGoodsId() { return goodsId; }
public int getQuantity() { return quantity; }
public long getPriceNQT() { return priceNQT; }
public int getDeliveryDeadlineTimestamp() { return deliveryDeadlineTimestamp; }
}
class DigitalGoodsDelivery extends AbstractAttachment {
private final long purchaseId;
private EncryptedData goods;
private final long discountNQT;
private final boolean goodsIsText;
DigitalGoodsDelivery(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.purchaseId = buffer.getLong();
int length = buffer.getInt();
goodsIsText = length < 0;
if (length < 0) {
length &= Integer.MAX_VALUE;
}
this.goods = EncryptedData.readEncryptedData(buffer, length, Constants.MAX_DGS_GOODS_LENGTH);
this.discountNQT = buffer.getLong();
}
DigitalGoodsDelivery(JSONObject attachmentData) {
super(attachmentData);
this.purchaseId = Convert.parseUnsignedLong((String) attachmentData.get("purchase"));
this.goods = new EncryptedData(Convert.parseHexString((String)attachmentData.get("goodsData")),
Convert.parseHexString((String)attachmentData.get("goodsNonce")));
this.discountNQT = Convert.parseLong(attachmentData.get("discountNQT"));
this.goodsIsText = Boolean.TRUE.equals(attachmentData.get("goodsIsText"));
}
public DigitalGoodsDelivery(long purchaseId, EncryptedData goods, boolean goodsIsText, long discountNQT) {
this.purchaseId = purchaseId;
this.goods = goods;
this.discountNQT = discountNQT;
this.goodsIsText = goodsIsText;
}
@Override
int getMySize() {
return 8 + 4 + goods.getSize() + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(purchaseId);
buffer.putInt(goodsIsText ? goods.getData().length | Integer.MIN_VALUE : goods.getData().length);
buffer.put(goods.getData());
buffer.put(goods.getNonce());
buffer.putLong(discountNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("purchase", Long.toUnsignedString(purchaseId));
attachment.put("goodsData", Convert.toHexString(goods.getData()));
attachment.put("goodsNonce", Convert.toHexString(goods.getNonce()));
attachment.put("discountNQT", discountNQT);
attachment.put("goodsIsText", goodsIsText);
}
@Override
public final TransactionType getTransactionType() {
return TransactionType.DigitalGoods.DELIVERY;
}
public final long getPurchaseId() {
return purchaseId;
}
public final EncryptedData getGoods() {
return goods;
}
final void setGoods(EncryptedData goods) {
this.goods = goods;
}
int getGoodsDataLength() {
return goods.getData().length;
}
public final long getDiscountNQT() {
return discountNQT;
}
public final boolean goodsIsText() {
return goodsIsText;
}
}
final class UnencryptedDigitalGoodsDelivery extends DigitalGoodsDelivery implements Encryptable {
private final byte[] goodsToEncrypt;
private final byte[] recipientPublicKey;
UnencryptedDigitalGoodsDelivery(JSONObject attachmentData) {
super(attachmentData);
setGoods(null);
String goodsToEncryptString = (String)attachmentData.get("goodsToEncrypt");
this.goodsToEncrypt = goodsIsText() ? Convert.toBytes(goodsToEncryptString)
: Convert.parseHexString(goodsToEncryptString);
this.recipientPublicKey = Convert.parseHexString((String)attachmentData.get("recipientPublicKey"));
}
public UnencryptedDigitalGoodsDelivery(long purchaseId, byte[] goodsToEncrypt, boolean goodsIsText, long discountNQT, byte[] recipientPublicKey) {
super(purchaseId, null, goodsIsText, discountNQT);
this.goodsToEncrypt = goodsToEncrypt;
this.recipientPublicKey = recipientPublicKey;
}
@Override
int getMySize() {
if (getGoods() == null) {
return 8 + 4 + EncryptedData.getEncryptedSize(getPlaintext()) + 8;
}
return super.getMySize();
}
@Override
void putMyBytes(ByteBuffer buffer) {
if (getGoods() == null) {
throw new NxtException.NotYetEncryptedException("Goods not yet encrypted");
}
super.putMyBytes(buffer);
}
@Override
void putMyJSON(JSONObject attachment) {
if (getGoods() == null) {
attachment.put("goodsToEncrypt", goodsIsText() ? Convert.toString(goodsToEncrypt) : Convert.toHexString(goodsToEncrypt));
attachment.put("recipientPublicKey", Convert.toHexString(recipientPublicKey));
attachment.put("purchase", Long.toUnsignedString(getPurchaseId()));
attachment.put("discountNQT", getDiscountNQT());
attachment.put("goodsIsText", goodsIsText());
} else {
super.putMyJSON(attachment);
}
}
@Override
public void encrypt(String secretPhrase) {
setGoods(EncryptedData.encrypt(getPlaintext(), secretPhrase, recipientPublicKey));
}
@Override
int getGoodsDataLength() {
return EncryptedData.getEncryptedDataLength(getPlaintext());
}
private byte[] getPlaintext() {
return Convert.compress(goodsToEncrypt);
}
}
final class DigitalGoodsFeedback extends AbstractAttachment {
private final long purchaseId;
DigitalGoodsFeedback(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.purchaseId = buffer.getLong();
}
DigitalGoodsFeedback(JSONObject attachmentData) {
super(attachmentData);
this.purchaseId = Convert.parseUnsignedLong((String)attachmentData.get("purchase"));
}
public DigitalGoodsFeedback(long purchaseId) {
this.purchaseId = purchaseId;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(purchaseId);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("purchase", Long.toUnsignedString(purchaseId));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.FEEDBACK;
}
public long getPurchaseId() { return purchaseId; }
}
final class DigitalGoodsRefund extends AbstractAttachment {
private final long purchaseId;
private final long refundNQT;
DigitalGoodsRefund(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.purchaseId = buffer.getLong();
this.refundNQT = buffer.getLong();
}
DigitalGoodsRefund(JSONObject attachmentData) {
super(attachmentData);
this.purchaseId = Convert.parseUnsignedLong((String)attachmentData.get("purchase"));
this.refundNQT = Convert.parseLong(attachmentData.get("refundNQT"));
}
public DigitalGoodsRefund(long purchaseId, long refundNQT) {
this.purchaseId = purchaseId;
this.refundNQT = refundNQT;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(purchaseId);
buffer.putLong(refundNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("purchase", Long.toUnsignedString(purchaseId));
attachment.put("refundNQT", refundNQT);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.DigitalGoods.REFUND;
}
public long getPurchaseId() { return purchaseId; }
public long getRefundNQT() { return refundNQT; }
}
final class AccountControlEffectiveBalanceLeasing extends AbstractAttachment {
private final int period;
AccountControlEffectiveBalanceLeasing(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.period = Short.toUnsignedInt(buffer.getShort());
}
AccountControlEffectiveBalanceLeasing(JSONObject attachmentData) {
super(attachmentData);
this.period = ((Long) attachmentData.get("period")).intValue();
}
public AccountControlEffectiveBalanceLeasing(int period) {
this.period = period;
}
@Override
int getMySize() {
return 2;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putShort((short)period);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("period", period);
}
@Override
public TransactionType getTransactionType() {
return TransactionType.AccountControl.EFFECTIVE_BALANCE_LEASING;
}
public int getPeriod() {
return period;
}
}
interface MonetarySystemAttachment {
long getCurrencyId();
}
final class MonetarySystemCurrencyIssuance extends AbstractAttachment {
private final String name;
private final String code;
private final String description;
private final byte type;
private final long initialSupply;
private final long reserveSupply;
private final long maxSupply;
private final int issuanceHeight;
private final long minReservePerUnitNQT;
private final int minDifficulty;
private final int maxDifficulty;
private final byte ruleset;
private final byte algorithm;
private final byte decimals;
MonetarySystemCurrencyIssuance(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
this.name = Convert.readString(buffer, buffer.get(), Constants.MAX_CURRENCY_NAME_LENGTH);
this.code = Convert.readString(buffer, buffer.get(), Constants.MAX_CURRENCY_CODE_LENGTH);
this.description = Convert.readString(buffer, buffer.getShort(), Constants.MAX_CURRENCY_DESCRIPTION_LENGTH);
this.type = buffer.get();
this.initialSupply = buffer.getLong();
this.reserveSupply = buffer.getLong();
this.maxSupply = buffer.getLong();
this.issuanceHeight = buffer.getInt();
this.minReservePerUnitNQT = buffer.getLong();
this.minDifficulty = buffer.get() & 0xFF;
this.maxDifficulty = buffer.get() & 0xFF;
this.ruleset = buffer.get();
this.algorithm = buffer.get();
this.decimals = buffer.get();
}
MonetarySystemCurrencyIssuance(JSONObject attachmentData) {
super(attachmentData);
this.name = (String)attachmentData.get("name");
this.code = (String)attachmentData.get("code");
this.description = (String)attachmentData.get("description");
this.type = ((Long)attachmentData.get("type")).byteValue();
this.initialSupply = Convert.parseLong(attachmentData.get("initialSupply"));
this.reserveSupply = Convert.parseLong(attachmentData.get("reserveSupply"));
this.maxSupply = Convert.parseLong(attachmentData.get("maxSupply"));
this.issuanceHeight = ((Long)attachmentData.get("issuanceHeight")).intValue();
this.minReservePerUnitNQT = Convert.parseLong(attachmentData.get("minReservePerUnitNQT"));
this.minDifficulty = ((Long)attachmentData.get("minDifficulty")).intValue();
this.maxDifficulty = ((Long)attachmentData.get("maxDifficulty")).intValue();
this.ruleset = ((Long)attachmentData.get("ruleset")).byteValue();
this.algorithm = ((Long)attachmentData.get("algorithm")).byteValue();
this.decimals = ((Long) attachmentData.get("decimals")).byteValue();
}
public MonetarySystemCurrencyIssuance(String name, String code, String description, byte type, long initialSupply, long reserveSupply,
long maxSupply, int issuanceHeight, long minReservePerUnitNQT, int minDifficulty, int maxDifficulty,
byte ruleset, byte algorithm, byte decimals) {
this.name = name;
this.code = code;
this.description = description;
this.type = type;
this.initialSupply = initialSupply;
this.reserveSupply = reserveSupply;
this.maxSupply = maxSupply;
this.issuanceHeight = issuanceHeight;
this.minReservePerUnitNQT = minReservePerUnitNQT;
this.minDifficulty = minDifficulty;
this.maxDifficulty = maxDifficulty;
this.ruleset = ruleset;
this.algorithm = algorithm;
this.decimals = decimals;
}
@Override
int getMySize() {
return 1 + Convert.toBytes(name).length + 1 + Convert.toBytes(code).length + 2 +
Convert.toBytes(description).length + 1 + 8 + 8 + 8 + 4 + 8 + 1 + 1 + 1 + 1 + 1;
}
@Override
void putMyBytes(ByteBuffer buffer) {
byte[] name = Convert.toBytes(this.name);
byte[] code = Convert.toBytes(this.code);
byte[] description = Convert.toBytes(this.description);
buffer.put((byte)name.length);
buffer.put(name);
buffer.put((byte)code.length);
buffer.put(code);
buffer.putShort((short) description.length);
buffer.put(description);
buffer.put(type);
buffer.putLong(initialSupply);
buffer.putLong(reserveSupply);
buffer.putLong(maxSupply);
buffer.putInt(issuanceHeight);
buffer.putLong(minReservePerUnitNQT);
buffer.put((byte)minDifficulty);
buffer.put((byte)maxDifficulty);
buffer.put(ruleset);
buffer.put(algorithm);
buffer.put(decimals);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("name", name);
attachment.put("code", code);
attachment.put("description", description);
attachment.put("type", type);
attachment.put("initialSupply", initialSupply);
attachment.put("reserveSupply", reserveSupply);
attachment.put("maxSupply", maxSupply);
attachment.put("issuanceHeight", issuanceHeight);
attachment.put("minReservePerUnitNQT", minReservePerUnitNQT);
attachment.put("minDifficulty", minDifficulty);
attachment.put("maxDifficulty", maxDifficulty);
attachment.put("ruleset", ruleset);
attachment.put("algorithm", algorithm);
attachment.put("decimals", decimals);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.CURRENCY_ISSUANCE;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public byte getType() {
return type;
}
public long getInitialSupply() {
return initialSupply;
}
public long getReserveSupply() {
return reserveSupply;
}
public long getMaxSupply() {
return maxSupply;
}
public int getIssuanceHeight() {
return issuanceHeight;
}
public long getMinReservePerUnitNQT() {
return minReservePerUnitNQT;
}
public int getMinDifficulty() {
return minDifficulty;
}
public int getMaxDifficulty() {
return maxDifficulty;
}
public byte getRuleset() {
return ruleset;
}
public byte getAlgorithm() {
return algorithm;
}
public byte getDecimals() {
return decimals;
}
}
final class MonetarySystemReserveIncrease extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
private final long amountPerUnitNQT;
MonetarySystemReserveIncrease(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
this.amountPerUnitNQT = buffer.getLong();
}
MonetarySystemReserveIncrease(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.amountPerUnitNQT = Convert.parseLong(attachmentData.get("amountPerUnitNQT"));
}
public MonetarySystemReserveIncrease(long currencyId, long amountPerUnitNQT) {
this.currencyId = currencyId;
this.amountPerUnitNQT = amountPerUnitNQT;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
buffer.putLong(amountPerUnitNQT);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("amountPerUnitNQT", amountPerUnitNQT);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.RESERVE_INCREASE;
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getAmountPerUnitNQT() {
return amountPerUnitNQT;
}
}
final class MonetarySystemReserveClaim extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
private final long units;
MonetarySystemReserveClaim(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
this.units = buffer.getLong();
}
MonetarySystemReserveClaim(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.units = Convert.parseLong(attachmentData.get("units"));
}
public MonetarySystemReserveClaim(long currencyId, long units) {
this.currencyId = currencyId;
this.units = units;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
buffer.putLong(units);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("units", units);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.RESERVE_CLAIM;
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getUnits() {
return units;
}
}
final class MonetarySystemCurrencyTransfer extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
private final long units;
MonetarySystemCurrencyTransfer(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
this.units = buffer.getLong();
}
MonetarySystemCurrencyTransfer(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.units = Convert.parseLong(attachmentData.get("units"));
}
public MonetarySystemCurrencyTransfer(long currencyId, long units) {
this.currencyId = currencyId;
this.units = units;
}
@Override
int getMySize() {
return 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
buffer.putLong(units);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("units", units);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.CURRENCY_TRANSFER;
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getUnits() {
return units;
}
}
final class MonetarySystemPublishExchangeOffer extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
private final long buyRateNQT;
private final long sellRateNQT;
private final long totalBuyLimit;
private final long totalSellLimit;
private final long initialBuySupply;
private final long initialSellSupply;
private final int expirationHeight;
MonetarySystemPublishExchangeOffer(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
this.buyRateNQT = buffer.getLong();
this.sellRateNQT = buffer.getLong();
this.totalBuyLimit = buffer.getLong();
this.totalSellLimit = buffer.getLong();
this.initialBuySupply = buffer.getLong();
this.initialSellSupply = buffer.getLong();
this.expirationHeight = buffer.getInt();
}
MonetarySystemPublishExchangeOffer(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.buyRateNQT = Convert.parseLong(attachmentData.get("buyRateNQT"));
this.sellRateNQT = Convert.parseLong(attachmentData.get("sellRateNQT"));
this.totalBuyLimit = Convert.parseLong(attachmentData.get("totalBuyLimit"));
this.totalSellLimit = Convert.parseLong(attachmentData.get("totalSellLimit"));
this.initialBuySupply = Convert.parseLong(attachmentData.get("initialBuySupply"));
this.initialSellSupply = Convert.parseLong(attachmentData.get("initialSellSupply"));
this.expirationHeight = ((Long)attachmentData.get("expirationHeight")).intValue();
}
public MonetarySystemPublishExchangeOffer(long currencyId, long buyRateNQT, long sellRateNQT, long totalBuyLimit,
long totalSellLimit, long initialBuySupply, long initialSellSupply, int expirationHeight) {
this.currencyId = currencyId;
this.buyRateNQT = buyRateNQT;
this.sellRateNQT = sellRateNQT;
this.totalBuyLimit = totalBuyLimit;
this.totalSellLimit = totalSellLimit;
this.initialBuySupply = initialBuySupply;
this.initialSellSupply = initialSellSupply;
this.expirationHeight = expirationHeight;
}
@Override
int getMySize() {
return 8 + 8 + 8 + 8 + 8 + 8 + 8 + 4;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
buffer.putLong(buyRateNQT);
buffer.putLong(sellRateNQT);
buffer.putLong(totalBuyLimit);
buffer.putLong(totalSellLimit);
buffer.putLong(initialBuySupply);
buffer.putLong(initialSellSupply);
buffer.putInt(expirationHeight);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("buyRateNQT", buyRateNQT);
attachment.put("sellRateNQT", sellRateNQT);
attachment.put("totalBuyLimit", totalBuyLimit);
attachment.put("totalSellLimit", totalSellLimit);
attachment.put("initialBuySupply", initialBuySupply);
attachment.put("initialSellSupply", initialSellSupply);
attachment.put("expirationHeight", expirationHeight);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.PUBLISH_EXCHANGE_OFFER;
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getBuyRateNQT() {
return buyRateNQT;
}
public long getSellRateNQT() {
return sellRateNQT;
}
public long getTotalBuyLimit() {
return totalBuyLimit;
}
public long getTotalSellLimit() {
return totalSellLimit;
}
public long getInitialBuySupply() {
return initialBuySupply;
}
public long getInitialSellSupply() {
return initialSellSupply;
}
public int getExpirationHeight() {
return expirationHeight;
}
}
abstract class MonetarySystemExchange extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
private final long rateNQT;
private final long units;
private MonetarySystemExchange(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
this.rateNQT = buffer.getLong();
this.units = buffer.getLong();
}
private MonetarySystemExchange(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.rateNQT = Convert.parseLong(attachmentData.get("rateNQT"));
this.units = Convert.parseLong(attachmentData.get("units"));
}
private MonetarySystemExchange(long currencyId, long rateNQT, long units) {
this.currencyId = currencyId;
this.rateNQT = rateNQT;
this.units = units;
}
@Override
int getMySize() {
return 8 + 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
buffer.putLong(rateNQT);
buffer.putLong(units);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("rateNQT", rateNQT);
attachment.put("units", units);
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getRateNQT() {
return rateNQT;
}
public long getUnits() {
return units;
}
}
final class MonetarySystemExchangeBuy extends MonetarySystemExchange {
MonetarySystemExchangeBuy(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
MonetarySystemExchangeBuy(JSONObject attachmentData) {
super(attachmentData);
}
public MonetarySystemExchangeBuy(long currencyId, long rateNQT, long units) {
super(currencyId, rateNQT, units);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.EXCHANGE_BUY;
}
}
final class MonetarySystemExchangeSell extends MonetarySystemExchange {
MonetarySystemExchangeSell(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
MonetarySystemExchangeSell(JSONObject attachmentData) {
super(attachmentData);
}
public MonetarySystemExchangeSell(long currencyId, long rateNQT, long units) {
super(currencyId, rateNQT, units);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.EXCHANGE_SELL;
}
}
final class MonetarySystemCurrencyMinting extends AbstractAttachment implements MonetarySystemAttachment {
private final long nonce;
private final long currencyId;
private final long units;
private final long counter;
MonetarySystemCurrencyMinting(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.nonce = buffer.getLong();
this.currencyId = buffer.getLong();
this.units = buffer.getLong();
this.counter = buffer.getLong();
}
MonetarySystemCurrencyMinting(JSONObject attachmentData) {
super(attachmentData);
this.nonce = Convert.parseLong(attachmentData.get("nonce"));
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
this.units = Convert.parseLong(attachmentData.get("units"));
this.counter = Convert.parseLong(attachmentData.get("counter"));
}
public MonetarySystemCurrencyMinting(long nonce, long currencyId, long units, long counter) {
this.nonce = nonce;
this.currencyId = currencyId;
this.units = units;
this.counter = counter;
}
@Override
int getMySize() {
return 8 + 8 + 8 + 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(nonce);
buffer.putLong(currencyId);
buffer.putLong(units);
buffer.putLong(counter);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("nonce", nonce);
attachment.put("currency", Long.toUnsignedString(currencyId));
attachment.put("units", units);
attachment.put("counter", counter);
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.CURRENCY_MINTING;
}
public long getNonce() {
return nonce;
}
@Override
public long getCurrencyId() {
return currencyId;
}
public long getUnits() {
return units;
}
public long getCounter() {
return counter;
}
}
final class MonetarySystemCurrencyDeletion extends AbstractAttachment implements MonetarySystemAttachment {
private final long currencyId;
MonetarySystemCurrencyDeletion(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.currencyId = buffer.getLong();
}
MonetarySystemCurrencyDeletion(JSONObject attachmentData) {
super(attachmentData);
this.currencyId = Convert.parseUnsignedLong((String)attachmentData.get("currency"));
}
public MonetarySystemCurrencyDeletion(long currencyId) {
this.currencyId = currencyId;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(currencyId);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("currency", Long.toUnsignedString(currencyId));
}
@Override
public TransactionType getTransactionType() {
return MonetarySystem.CURRENCY_DELETION;
}
@Override
public long getCurrencyId() {
return currencyId;
}
}
final class ShufflingCreation extends AbstractAttachment {
private final long holdingId;
private final HoldingType holdingType;
private final long amount;
private final byte participantCount;
private final short registrationPeriod;
ShufflingCreation(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.holdingId = buffer.getLong();
this.holdingType = HoldingType.get(buffer.get());
this.amount = buffer.getLong();
this.participantCount = buffer.get();
this.registrationPeriod = buffer.getShort();
}
ShufflingCreation(JSONObject attachmentData) {
super(attachmentData);
this.holdingId = Convert.parseUnsignedLong((String) attachmentData.get("holding"));
this.holdingType = HoldingType.get(((Long)attachmentData.get("holdingType")).byteValue());
this.amount = Convert.parseLong(attachmentData.get("amount"));
this.participantCount = ((Long)attachmentData.get("participantCount")).byteValue();
this.registrationPeriod = ((Long)attachmentData.get("registrationPeriod")).shortValue();
}
public ShufflingCreation(long holdingId, HoldingType holdingType, long amount, byte participantCount, short registrationPeriod) {
this.holdingId = holdingId;
this.holdingType = holdingType;
this.amount = amount;
this.participantCount = participantCount;
this.registrationPeriod = registrationPeriod;
}
@Override
int getMySize() {
return 8 + 1 + 8 + 1 + 2;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(holdingId);
buffer.put(holdingType.getCode());
buffer.putLong(amount);
buffer.put(participantCount);
buffer.putShort(registrationPeriod);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("holding", Long.toUnsignedString(holdingId));
attachment.put("holdingType", holdingType.getCode());
attachment.put("amount", amount);
attachment.put("participantCount", participantCount);
attachment.put("registrationPeriod", registrationPeriod);
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_CREATION;
}
public long getHoldingId() {
return holdingId;
}
public HoldingType getHoldingType() {
return holdingType;
}
public long getAmount() {
return amount;
}
public byte getParticipantCount() {
return participantCount;
}
public short getRegistrationPeriod() {
return registrationPeriod;
}
}
interface ShufflingAttachment extends Attachment {
long getShufflingId();
byte[] getShufflingStateHash();
}
abstract class AbstractShufflingAttachment extends AbstractAttachment implements ShufflingAttachment {
private final long shufflingId;
private final byte[] shufflingStateHash;
private AbstractShufflingAttachment(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.shufflingId = buffer.getLong();
this.shufflingStateHash = new byte[32];
buffer.get(this.shufflingStateHash);
}
private AbstractShufflingAttachment(JSONObject attachmentData) {
super(attachmentData);
this.shufflingId = Convert.parseUnsignedLong((String) attachmentData.get("shuffling"));
this.shufflingStateHash = Convert.parseHexString((String) attachmentData.get("shufflingStateHash"));
}
private AbstractShufflingAttachment(long shufflingId, byte[] shufflingStateHash) {
this.shufflingId = shufflingId;
this.shufflingStateHash = shufflingStateHash;
}
@Override
int getMySize() {
return 8 + 32;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(shufflingId);
buffer.put(shufflingStateHash);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("shuffling", Long.toUnsignedString(shufflingId));
attachment.put("shufflingStateHash", Convert.toHexString(shufflingStateHash));
}
@Override
public final long getShufflingId() {
return shufflingId;
}
@Override
public final byte[] getShufflingStateHash() {
return shufflingStateHash;
}
}
final class ShufflingRegistration extends AbstractAttachment implements ShufflingAttachment {
private final byte[] shufflingFullHash;
ShufflingRegistration(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.shufflingFullHash = new byte[32];
buffer.get(this.shufflingFullHash);
}
ShufflingRegistration(JSONObject attachmentData) {
super(attachmentData);
this.shufflingFullHash = Convert.parseHexString((String) attachmentData.get("shufflingFullHash"));
}
public ShufflingRegistration(byte[] shufflingFullHash) {
this.shufflingFullHash = shufflingFullHash;
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_REGISTRATION;
}
@Override
int getMySize() {
return 32;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.put(shufflingFullHash);
}
@Override
void putMyJSON(JSONObject attachment) {
attachment.put("shufflingFullHash", Convert.toHexString(shufflingFullHash));
}
@Override
public long getShufflingId() {
return Convert.fullHashToId(shufflingFullHash);
}
@Override
public byte[] getShufflingStateHash() {
return shufflingFullHash;
}
}
final class ShufflingProcessing extends AbstractShufflingAttachment implements Prunable {
private static final byte[] emptyDataHash = Crypto.sha256().digest();
static ShufflingProcessing parse(JSONObject attachmentData) throws NxtException.NotValidException {
if (!Appendix.hasAppendix(ShufflingTransaction.SHUFFLING_PROCESSING.getName(), attachmentData)) {
return null;
}
return new ShufflingProcessing(attachmentData);
}
private volatile byte[][] data;
private final byte[] hash;
ShufflingProcessing(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.hash = new byte[32];
buffer.get(hash);
this.data = Arrays.equals(hash, emptyDataHash) ? Convert.EMPTY_BYTES : null;
}
ShufflingProcessing(JSONObject attachmentData) {
super(attachmentData);
JSONArray jsonArray = (JSONArray)attachmentData.get("data");
if (jsonArray != null) {
this.data = new byte[jsonArray.size()][];
for (int i = 0; i < this.data.length; i++) {
this.data[i] = Convert.parseHexString((String) jsonArray.get(i));
}
this.hash = null;
} else {
this.hash = Convert.parseHexString(Convert.emptyToNull((String)attachmentData.get("hash")));
this.data = Arrays.equals(hash, emptyDataHash) ? Convert.EMPTY_BYTES : null;
}
}
ShufflingProcessing(long shufflingId, byte[][] data, byte[] shufflingStateHash) {
super(shufflingId, shufflingStateHash);
this.data = data;
this.hash = null;
}
@Override
int getMyFullSize() {
int size = super.getMySize();
if (data != null) {
size += 1;
for (byte[] bytes : data) {
size += 4;
size += bytes.length;
}
}
return size / 2; // just lie
}
@Override
int getMySize() {
return super.getMySize() + 32;
}
@Override
void putMyBytes(ByteBuffer buffer) {
super.putMyBytes(buffer);
buffer.put(getHash());
}
@Override
void putMyJSON(JSONObject attachment) {
super.putMyJSON(attachment);
if (data != null) {
JSONArray jsonArray = new JSONArray();
attachment.put("data", jsonArray);
for (byte[] bytes : data) {
jsonArray.add(Convert.toHexString(bytes));
}
}
attachment.put("hash", Convert.toHexString(getHash()));
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_PROCESSING;
}
@Override
public byte[] getHash() {
if (hash != null) {
return hash;
} else if (data != null) {
MessageDigest digest = Crypto.sha256();
for (byte[] bytes : data) {
digest.update(bytes);
}
return digest.digest();
} else {
throw new IllegalStateException("Both hash and data are null");
}
}
public byte[][] getData() {
return data;
}
@Override
void loadPrunable(Transaction transaction, boolean includeExpiredPrunable) {
if (data == null && shouldLoadPrunable(transaction, includeExpiredPrunable)) {
data = ShufflingParticipant.getData(getShufflingId(), transaction.getSenderId());
}
}
@Override
public boolean hasPrunableData() {
return data != null;
}
@Override
public void restorePrunableData(Transaction transaction, int blockTimestamp, int height) {
ShufflingParticipant.restoreData(getShufflingId(), transaction.getSenderId(), getData(), transaction.getTimestamp(), height);
}
}
final class ShufflingRecipients extends AbstractShufflingAttachment {
private final byte[][] recipientPublicKeys;
ShufflingRecipients(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
int count = buffer.get();
if (count > Constants.MAX_NUMBER_OF_SHUFFLING_PARTICIPANTS || count < 0) {
throw new NxtException.NotValidException("Invalid data count " + count);
}
this.recipientPublicKeys = new byte[count][];
for (int i = 0; i < count; i++) {
this.recipientPublicKeys[i] = new byte[32];
buffer.get(this.recipientPublicKeys[i]);
}
}
ShufflingRecipients(JSONObject attachmentData) {
super(attachmentData);
JSONArray jsonArray = (JSONArray)attachmentData.get("recipientPublicKeys");
this.recipientPublicKeys = new byte[jsonArray.size()][];
for (int i = 0; i < this.recipientPublicKeys.length; i++) {
this.recipientPublicKeys[i] = Convert.parseHexString((String)jsonArray.get(i));
}
}
ShufflingRecipients(long shufflingId, byte[][] recipientPublicKeys, byte[] shufflingStateHash) {
super(shufflingId, shufflingStateHash);
this.recipientPublicKeys = recipientPublicKeys;
}
@Override
int getMySize() {
int size = super.getMySize();
size += 1;
size += 32 * recipientPublicKeys.length;
return size;
}
@Override
void putMyBytes(ByteBuffer buffer) {
super.putMyBytes(buffer);
buffer.put((byte)recipientPublicKeys.length);
for (byte[] bytes : recipientPublicKeys) {
buffer.put(bytes);
}
}
@Override
void putMyJSON(JSONObject attachment) {
super.putMyJSON(attachment);
JSONArray jsonArray = new JSONArray();
attachment.put("recipientPublicKeys", jsonArray);
for (byte[] bytes : recipientPublicKeys) {
jsonArray.add(Convert.toHexString(bytes));
}
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_RECIPIENTS;
}
public byte[][] getRecipientPublicKeys() {
return recipientPublicKeys;
}
}
final class ShufflingVerification extends AbstractShufflingAttachment {
ShufflingVerification(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
}
ShufflingVerification(JSONObject attachmentData) {
super(attachmentData);
}
public ShufflingVerification(long shufflingId, byte[] shufflingStateHash) {
super(shufflingId, shufflingStateHash);
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_VERIFICATION;
}
}
final class ShufflingCancellation extends AbstractShufflingAttachment {
private final byte[][] blameData;
private final byte[][] keySeeds;
private final long cancellingAccountId;
ShufflingCancellation(ByteBuffer buffer, byte transactionVersion) throws NxtException.NotValidException {
super(buffer, transactionVersion);
int count = buffer.get();
if (count > Constants.MAX_NUMBER_OF_SHUFFLING_PARTICIPANTS || count <= 0) {
throw new NxtException.NotValidException("Invalid data count " + count);
}
this.blameData = new byte[count][];
for (int i = 0; i < count; i++) {
int size = buffer.getInt();
if (size > Constants.MAX_PAYLOAD_LENGTH) {
throw new NxtException.NotValidException("Invalid data size " + size);
}
this.blameData[i] = new byte[size];
buffer.get(this.blameData[i]);
}
count = buffer.get();
if (count > Constants.MAX_NUMBER_OF_SHUFFLING_PARTICIPANTS || count <= 0) {
throw new NxtException.NotValidException("Invalid keySeeds count " + count);
}
this.keySeeds = new byte[count][];
for (int i = 0; i < count; i++) {
this.keySeeds[i] = new byte[32];
buffer.get(this.keySeeds[i]);
}
this.cancellingAccountId = buffer.getLong();
}
ShufflingCancellation(JSONObject attachmentData) {
super(attachmentData);
JSONArray jsonArray = (JSONArray)attachmentData.get("blameData");
this.blameData = new byte[jsonArray.size()][];
for (int i = 0; i < this.blameData.length; i++) {
this.blameData[i] = Convert.parseHexString((String)jsonArray.get(i));
}
jsonArray = (JSONArray)attachmentData.get("keySeeds");
this.keySeeds = new byte[jsonArray.size()][];
for (int i = 0; i < this.keySeeds.length; i++) {
this.keySeeds[i] = Convert.parseHexString((String)jsonArray.get(i));
}
this.cancellingAccountId = Convert.parseUnsignedLong((String) attachmentData.get("cancellingAccount"));
}
ShufflingCancellation(long shufflingId, byte[][] blameData, byte[][] keySeeds, byte[] shufflingStateHash, long cancellingAccountId) {
super(shufflingId, shufflingStateHash);
this.blameData = blameData;
this.keySeeds = keySeeds;
this.cancellingAccountId = cancellingAccountId;
}
@Override
public TransactionType getTransactionType() {
return ShufflingTransaction.SHUFFLING_CANCELLATION;
}
@Override
int getMySize() {
int size = super.getMySize();
size += 1;
for (byte[] bytes : blameData) {
size += 4;
size += bytes.length;
}
size += 1;
size += 32 * keySeeds.length;
size += 8;
return size;
}
@Override
void putMyBytes(ByteBuffer buffer) {
super.putMyBytes(buffer);
buffer.put((byte) blameData.length);
for (byte[] bytes : blameData) {
buffer.putInt(bytes.length);
buffer.put(bytes);
}
buffer.put((byte) keySeeds.length);
for (byte[] bytes : keySeeds) {
buffer.put(bytes);
}
buffer.putLong(cancellingAccountId);
}
@Override
void putMyJSON(JSONObject attachment) {
super.putMyJSON(attachment);
JSONArray jsonArray = new JSONArray();
attachment.put("blameData", jsonArray);
for (byte[] bytes : blameData) {
jsonArray.add(Convert.toHexString(bytes));
}
jsonArray = new JSONArray();
attachment.put("keySeeds", jsonArray);
for (byte[] bytes : keySeeds) {
jsonArray.add(Convert.toHexString(bytes));
}
if (cancellingAccountId != 0) {
attachment.put("cancellingAccount", Long.toUnsignedString(cancellingAccountId));
}
}
public byte[][] getBlameData() {
return blameData;
}
public byte[][] getKeySeeds() {
return keySeeds;
}
public long getCancellingAccountId() {
return cancellingAccountId;
}
byte[] getHash() {
MessageDigest digest = Crypto.sha256();
for (byte[] bytes : blameData) {
digest.update(bytes);
}
return digest.digest();
}
}
abstract class TaggedDataAttachment extends AbstractAttachment implements Prunable {
private final String name;
private final String description;
private final String tags;
private final String type;
private final String channel;
private final boolean isText;
private final String filename;
private final byte[] data;
private volatile TaggedData taggedData;
private TaggedDataAttachment(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.name = null;
this.description = null;
this.tags = null;
this.type = null;
this.channel = null;
this.isText = false;
this.filename = null;
this.data = null;
}
private TaggedDataAttachment(JSONObject attachmentData) {
super(attachmentData);
String dataJSON = (String) attachmentData.get("data");
if (dataJSON != null) {
this.name = (String) attachmentData.get("name");
this.description = (String) attachmentData.get("description");
this.tags = (String) attachmentData.get("tags");
this.type = (String) attachmentData.get("type");
this.channel = Convert.nullToEmpty((String) attachmentData.get("channel"));
this.isText = Boolean.TRUE.equals(attachmentData.get("isText"));
this.data = isText ? Convert.toBytes(dataJSON) : Convert.parseHexString(dataJSON);
this.filename = (String) attachmentData.get("filename");
} else {
this.name = null;
this.description = null;
this.tags = null;
this.type = null;
this.channel = null;
this.isText = false;
this.filename = null;
this.data = null;
}
}
private TaggedDataAttachment(String name, String description, String tags, String type, String channel, boolean isText, String filename, byte[] data) {
this.name = name;
this.description = description;
this.tags = tags;
this.type = type;
this.channel = channel;
this.isText = isText;
this.data = data;
this.filename = filename;
}
@Override
final int getMyFullSize() {
if (getData() == null) {
return 0;
}
return Convert.toBytes(getName()).length + Convert.toBytes(getDescription()).length + Convert.toBytes(getType()).length
+ Convert.toBytes(getChannel()).length + Convert.toBytes(getTags()).length + Convert.toBytes(getFilename()).length + getData().length;
}
@Override
void putMyJSON(JSONObject attachment) {
if (taggedData != null) {
attachment.put("name", taggedData.getName());
attachment.put("description", taggedData.getDescription());
attachment.put("tags", taggedData.getTags());
attachment.put("type", taggedData.getType());
attachment.put("channel", taggedData.getChannel());
attachment.put("isText", taggedData.isText());
attachment.put("filename", taggedData.getFilename());
attachment.put("data", taggedData.isText() ? Convert.toString(taggedData.getData()) : Convert.toHexString(taggedData.getData()));
} else if (data != null) {
attachment.put("name", name);
attachment.put("description", description);
attachment.put("tags", tags);
attachment.put("type", type);
attachment.put("channel", channel);
attachment.put("isText", isText);
attachment.put("filename", filename);
attachment.put("data", isText ? Convert.toString(data) : Convert.toHexString(data));
}
}
@Override
public byte[] getHash() {
if (data == null) {
return null;
}
MessageDigest digest = Crypto.sha256();
digest.update(Convert.toBytes(name));
digest.update(Convert.toBytes(description));
digest.update(Convert.toBytes(tags));
digest.update(Convert.toBytes(type));
digest.update(Convert.toBytes(channel));
digest.update((byte)(isText ? 1 : 0));
digest.update(Convert.toBytes(filename));
digest.update(data);
return digest.digest();
}
public final String getName() {
if (taggedData != null) {
return taggedData.getName();
}
return name;
}
public final String getDescription() {
if (taggedData != null) {
return taggedData.getDescription();
}
return description;
}
public final String getTags() {
if (taggedData != null) {
return taggedData.getTags();
}
return tags;
}
public final String getType() {
if (taggedData != null) {
return taggedData.getType();
}
return type;
}
public final String getChannel() {
if (taggedData != null) {
return taggedData.getChannel();
}
return channel;
}
public final boolean isText() {
if (taggedData != null) {
return taggedData.isText();
}
return isText;
}
public final String getFilename() {
if (taggedData != null) {
return taggedData.getFilename();
}
return filename;
}
public final byte[] getData() {
if (taggedData != null) {
return taggedData.getData();
}
return data;
}
@Override
void loadPrunable(Transaction transaction, boolean includeExpiredPrunable) {
if (data == null && taggedData == null && shouldLoadPrunable(transaction, includeExpiredPrunable)) {
taggedData = TaggedData.getData(getTaggedDataId(transaction));
}
}
@Override
public boolean hasPrunableData() {
return (taggedData != null || data != null);
}
abstract long getTaggedDataId(Transaction transaction);
}
final class TaggedDataUpload extends TaggedDataAttachment {
static TaggedDataUpload parse(JSONObject attachmentData) {
if (!Appendix.hasAppendix(TransactionType.Data.TAGGED_DATA_UPLOAD.getName(), attachmentData)) {
return null;
}
return new TaggedDataUpload(attachmentData);
}
private final byte[] hash;
TaggedDataUpload(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.hash = new byte[32];
buffer.get(hash);
}
TaggedDataUpload(JSONObject attachmentData) {
super(attachmentData);
String dataJSON = (String) attachmentData.get("data");
if (dataJSON == null) {
this.hash = Convert.parseHexString(Convert.emptyToNull((String)attachmentData.get("hash")));
} else {
this.hash = null;
}
}
public TaggedDataUpload(String name, String description, String tags, String type, String channel, boolean isText,
String filename, byte[] data) throws NxtException.NotValidException {
super(name, description, tags, type, channel, isText, filename, data);
this.hash = null;
if (isText && !Arrays.equals(data, Convert.toBytes(Convert.toString(data)))) {
throw new NxtException.NotValidException("Data is not UTF-8 text");
}
}
@Override
int getMySize() {
return 32;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.put(getHash());
}
@Override
void putMyJSON(JSONObject attachment) {
super.putMyJSON(attachment);
attachment.put("hash", Convert.toHexString(getHash()));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Data.TAGGED_DATA_UPLOAD;
}
@Override
public byte[] getHash() {
if (hash != null) {
return hash;
}
return super.getHash();
}
@Override
long getTaggedDataId(Transaction transaction) {
return transaction.getId();
}
@Override
public void restorePrunableData(Transaction transaction, int blockTimestamp, int height) {
TaggedData.restore(transaction, this, blockTimestamp, height);
}
}
final class TaggedDataExtend extends TaggedDataAttachment {
static TaggedDataExtend parse(JSONObject attachmentData) {
if (!Appendix.hasAppendix(TransactionType.Data.TAGGED_DATA_EXTEND.getName(), attachmentData)) {
return null;
}
return new TaggedDataExtend(attachmentData);
}
private volatile byte[] hash;
private final long taggedDataId;
private final boolean jsonIsPruned;
TaggedDataExtend(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
this.taggedDataId = buffer.getLong();
this.jsonIsPruned = false;
}
TaggedDataExtend(JSONObject attachmentData) {
super(attachmentData);
this.taggedDataId = Convert.parseUnsignedLong((String)attachmentData.get("taggedData"));
this.jsonIsPruned = attachmentData.get("data") == null;
}
public TaggedDataExtend(TaggedData taggedData) {
super(taggedData.getName(), taggedData.getDescription(), taggedData.getTags(), taggedData.getType(),
taggedData.getChannel(), taggedData.isText(), taggedData.getFilename(), taggedData.getData());
this.taggedDataId = taggedData.getId();
this.jsonIsPruned = false;
}
@Override
int getMySize() {
return 8;
}
@Override
void putMyBytes(ByteBuffer buffer) {
buffer.putLong(taggedDataId);
}
@Override
void putMyJSON(JSONObject attachment) {
super.putMyJSON(attachment);
attachment.put("taggedData", Long.toUnsignedString(taggedDataId));
}
@Override
public TransactionType getTransactionType() {
return TransactionType.Data.TAGGED_DATA_EXTEND;
}
public long getTaggedDataId() {
return taggedDataId;
}
@Override
public byte[] getHash() {
if (hash == null) {
hash = super.getHash();
}
if (hash == null) {
TaggedDataUpload taggedDataUpload = (TaggedDataUpload)TransactionDb.findTransaction(taggedDataId).getAttachment();
hash = taggedDataUpload.getHash();
}
return hash;
}
@Override
long getTaggedDataId(Transaction transaction) {
return taggedDataId;
}
boolean jsonIsPruned() {
return jsonIsPruned;
}
@Override
public void restorePrunableData(Transaction transaction, int blockTimestamp, int height) {
}
}
final class SetPhasingOnly extends AbstractAttachment {
private final PhasingParams phasingParams;
private final long maxFees;
private final short minDuration;
private final short maxDuration;
public SetPhasingOnly(PhasingParams params, long maxFees, short minDuration, short maxDuration) {
phasingParams = params;
this.maxFees = maxFees;
this.minDuration = minDuration;
this.maxDuration = maxDuration;
}
SetPhasingOnly(ByteBuffer buffer, byte transactionVersion) {
super(buffer, transactionVersion);
phasingParams = new PhasingParams(buffer);
maxFees = buffer.getLong();
minDuration = buffer.getShort();
maxDuration = buffer.getShort();
}
SetPhasingOnly(JSONObject attachmentData) {
super(attachmentData);
JSONObject phasingControlParams = (JSONObject) attachmentData.get("phasingControlParams");
phasingParams = new PhasingParams(phasingControlParams);
maxFees = Convert.parseLong(attachmentData.get("controlMaxFees"));
minDuration = ((Long)attachmentData.get("controlMinDuration")).shortValue();
maxDuration = ((Long)attachmentData.get("controlMaxDuration")).shortValue();
}
@Override
public TransactionType getTransactionType() {
return TransactionType.AccountControl.SET_PHASING_ONLY;
}
@Override
int getMySize() {
return phasingParams.getMySize() + 8 + 2 + 2;
}
@Override
void putMyBytes(ByteBuffer buffer) {
phasingParams.putMyBytes(buffer);
buffer.putLong(maxFees);
buffer.putShort(minDuration);
buffer.putShort(maxDuration);
}
@Override
void putMyJSON(JSONObject json) {
JSONObject phasingControlParams = new JSONObject();
phasingParams.putMyJSON(phasingControlParams);
json.put("phasingControlParams", phasingControlParams);
json.put("controlMaxFees", maxFees);
json.put("controlMinDuration", minDuration);
json.put("controlMaxDuration", maxDuration);
}
public PhasingParams getPhasingParams() {
return phasingParams;
}
public long getMaxFees() {
return maxFees;
}
public short getMinDuration() {
return minDuration;
}
public short getMaxDuration() {
return maxDuration;
}
}
}