forked from Qortal/qortal
Removed code for providing compatibility with Qora v1
Qortal is never going to continue off the old Qora blockchain, so removed all code regarding compatibility. Removals include: * various blockchain "feature triggers" * special Qora-only broken code for various transaction signatures * "old" asset pricing / trading * pre-group txGroupId field in transactions * compatibility unit tests Possibly safe for roll-out on pre-genesis blockchain?
This commit is contained in:
parent
136188339d
commit
bd521baade
@ -11,7 +11,6 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.asset.AssetData;
|
||||
import org.qortal.data.asset.OrderData;
|
||||
import org.qortal.data.asset.TradeData;
|
||||
@ -29,7 +28,6 @@ public class Order {
|
||||
private OrderData orderData;
|
||||
|
||||
// Used quite a bit
|
||||
private final boolean isOurOrderNewPricing;
|
||||
private final long haveAssetId;
|
||||
private final long wantAssetId;
|
||||
|
||||
@ -47,7 +45,6 @@ public class Order {
|
||||
this.repository = repository;
|
||||
this.orderData = orderData;
|
||||
|
||||
this.isOurOrderNewPricing = this.orderData.getTimestamp() >= BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
this.haveAssetId = this.orderData.getHaveAssetId();
|
||||
this.wantAssetId = this.orderData.getWantAssetId();
|
||||
}
|
||||
@ -130,7 +127,7 @@ public class Order {
|
||||
|
||||
/** Calculate price pair. (e.g. QORT/GOLD)
|
||||
* <p>
|
||||
* Under 'new' pricing scheme, lowest-assetID asset is first,
|
||||
* Lowest-assetID asset is first,
|
||||
* so if QORT has assetID 0 and GOLD has assetID 10, then
|
||||
* the pricing pair is QORT/GOLD.
|
||||
* <p>
|
||||
@ -141,7 +138,7 @@ public class Order {
|
||||
AssetData haveAssetData = getHaveAsset();
|
||||
AssetData wantAssetData = getWantAsset();
|
||||
|
||||
if (isOurOrderNewPricing && haveAssetId > wantAssetId)
|
||||
if (haveAssetId > wantAssetId)
|
||||
cachedPricePair = wantAssetData.getName() + "/" + haveAssetData.getName();
|
||||
else
|
||||
cachedPricePair = haveAssetData.getName() + "/" + wantAssetData.getName();
|
||||
@ -151,8 +148,8 @@ public class Order {
|
||||
private BigDecimal calcHaveAssetCommittment() {
|
||||
BigDecimal committedCost = this.orderData.getAmount();
|
||||
|
||||
// If 'new' pricing and "amount" is in want-asset then we need to convert
|
||||
if (isOurOrderNewPricing && haveAssetId < wantAssetId)
|
||||
// If "amount" is in want-asset then we need to convert
|
||||
if (haveAssetId < wantAssetId)
|
||||
committedCost = committedCost.multiply(this.orderData.getPrice()).setScale(8, RoundingMode.HALF_UP);
|
||||
|
||||
return committedCost;
|
||||
@ -162,8 +159,8 @@ public class Order {
|
||||
private BigDecimal calcHaveAssetRefund() {
|
||||
BigDecimal refund = getAmountLeft();
|
||||
|
||||
// If 'new' pricing and "amount" is in want-asset then we need to convert
|
||||
if (isOurOrderNewPricing && haveAssetId < wantAssetId)
|
||||
// If "amount" is in want-asset then we need to convert
|
||||
if (haveAssetId < wantAssetId)
|
||||
refund = refund.multiply(this.orderData.getPrice()).setScale(8, RoundingMode.HALF_UP);
|
||||
|
||||
return refund;
|
||||
@ -192,27 +189,19 @@ public class Order {
|
||||
/**
|
||||
* Returns AssetData for asset in effect for "amount" field.
|
||||
* <p>
|
||||
* For 'old' pricing, this is the have-asset.<br>
|
||||
* For 'new' pricing, this is the asset with highest assetID.
|
||||
* This is the asset with highest assetID.
|
||||
*/
|
||||
public AssetData getAmountAsset() throws DataException {
|
||||
if (isOurOrderNewPricing && wantAssetId > haveAssetId)
|
||||
return getWantAsset();
|
||||
else
|
||||
return getHaveAsset();
|
||||
return (wantAssetId > haveAssetId) ? getWantAsset() : getHaveAsset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AssetData for other (return) asset traded.
|
||||
* <p>
|
||||
* For 'old' pricing, this is the want-asset.<br>
|
||||
* For 'new' pricing, this is the asset with lowest assetID.
|
||||
* This is the asset with lowest assetID.
|
||||
*/
|
||||
public AssetData getReturnAsset() throws DataException {
|
||||
if (isOurOrderNewPricing && haveAssetId < wantAssetId)
|
||||
return getHaveAsset();
|
||||
else
|
||||
return getWantAsset();
|
||||
return (haveAssetId < wantAssetId) ? getHaveAsset() : getWantAsset();
|
||||
}
|
||||
|
||||
// Processing
|
||||
@ -227,8 +216,6 @@ public class Order {
|
||||
|
||||
// NOTE: the following values are specific to passed orderData, not the same as class instance values!
|
||||
|
||||
final boolean isOrderNewAssetPricing = orderData.getTimestamp() >= BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
|
||||
// Cached for readability
|
||||
final long _haveAssetId = orderData.getHaveAssetId();
|
||||
final long _wantAssetId = orderData.getWantAssetId();
|
||||
@ -236,15 +223,15 @@ public class Order {
|
||||
final AssetData haveAssetData = this.repository.getAssetRepository().fromAssetId(_haveAssetId);
|
||||
final AssetData wantAssetData = this.repository.getAssetRepository().fromAssetId(_wantAssetId);
|
||||
|
||||
final long amountAssetId = (isOurOrderNewPricing && _wantAssetId > _haveAssetId) ? _wantAssetId : _haveAssetId;
|
||||
final long returnAssetId = (isOurOrderNewPricing && _haveAssetId < _wantAssetId) ? _haveAssetId : _wantAssetId;
|
||||
final long amountAssetId = (_wantAssetId > _haveAssetId) ? _wantAssetId : _haveAssetId;
|
||||
final long returnAssetId = (_haveAssetId < _wantAssetId) ? _haveAssetId : _wantAssetId;
|
||||
|
||||
final AssetData amountAssetData = this.repository.getAssetRepository().fromAssetId(amountAssetId);
|
||||
final AssetData returnAssetData = this.repository.getAssetRepository().fromAssetId(returnAssetId);
|
||||
|
||||
LOGGER.debug(String.format("%s %s", orderPrefix, Base58.encode(orderData.getOrderId())));
|
||||
|
||||
LOGGER.trace(String.format("%s have %s, want %s. '%s' pricing scheme.", weThey, haveAssetData.getName(), wantAssetData.getName(), isOrderNewAssetPricing ? "new" : "old"));
|
||||
LOGGER.trace(String.format("%s have %s, want %s.", weThey, haveAssetData.getName(), wantAssetData.getName()));
|
||||
|
||||
LOGGER.trace(String.format("%s amount: %s (ordered) - %s (fulfilled) = %s %s left", ourTheir,
|
||||
orderData.getAmount().stripTrailingZeros().toPlainString(),
|
||||
@ -266,9 +253,9 @@ public class Order {
|
||||
AssetData wantAssetData = getWantAsset();
|
||||
|
||||
/** The asset while working out amount that matches. */
|
||||
AssetData matchingAssetData = isOurOrderNewPricing ? getAmountAsset() : wantAssetData;
|
||||
AssetData matchingAssetData = getAmountAsset();
|
||||
/** The return asset traded if trade completes. */
|
||||
AssetData returnAssetData = isOurOrderNewPricing ? getReturnAsset() : haveAssetData;
|
||||
AssetData returnAssetData = getReturnAsset();
|
||||
|
||||
// Subtract have-asset from creator
|
||||
Account creator = new PublicKeyAccount(this.repository, this.orderData.getCreatorPublicKey());
|
||||
@ -281,7 +268,7 @@ public class Order {
|
||||
|
||||
// Fetch corresponding open orders that might potentially match, hence reversed want/have assetIDs.
|
||||
// Returned orders are sorted with lowest "price" first.
|
||||
List<OrderData> orders = assetRepository.getOpenOrdersForTrading(wantAssetId, haveAssetId, isOurOrderNewPricing ? this.orderData.getPrice() : null);
|
||||
List<OrderData> orders = assetRepository.getOpenOrdersForTrading(wantAssetId, haveAssetId, this.orderData.getPrice());
|
||||
LOGGER.trace("Open orders fetched from repository: " + orders.size());
|
||||
|
||||
if (orders.isEmpty())
|
||||
@ -290,27 +277,7 @@ public class Order {
|
||||
// Attempt to match orders
|
||||
|
||||
/*
|
||||
* Potential matching order example ("old"):
|
||||
*
|
||||
* Our order:
|
||||
* haveAssetId=[GOLD], wantAssetId=0 (QORT), amount=40 (GOLD), price=486 (QORT/GOLD)
|
||||
* This translates to "we have 40 GOLD and want QORT at a price of 486 QORT per GOLD"
|
||||
* If our order matched, we'd end up with 40 * 486 = 19,440 QORT.
|
||||
*
|
||||
* Their order:
|
||||
* haveAssetId=0 (QORT), wantAssetId=[GOLD], amount=20,000 (QORT), price=0.00205761 (GOLD/QORT)
|
||||
* This translates to "they have 20,000 QORT and want GOLD at a price of 0.00205761 GOLD per QORT"
|
||||
*
|
||||
* Their price, converted into 'our' units of QORT/GOLD, is: 1 / 0.00205761 = 486.00074844 QORT/GOLD.
|
||||
* This is better than our requested 486 QORT/GOLD so this order matches.
|
||||
*
|
||||
* Using their price, we end up with 40 * 486.00074844 = 19440.02993760 QORT. They end up with 40 GOLD.
|
||||
*
|
||||
* If their order had 19,440 QORT left, only 19,440 * 0.00205761 = 39.99993840 GOLD would be traded.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Potential matching order example ("new"):
|
||||
* Potential matching order example:
|
||||
*
|
||||
* Our order:
|
||||
* haveAssetId=[GOLD], wantAssetId=0 (QORT), amount=40 (GOLD), price=486 (QORT/GOLD)
|
||||
@ -333,44 +300,21 @@ public class Order {
|
||||
for (OrderData theirOrderData : orders) {
|
||||
logOrder("Considering order", false, theirOrderData);
|
||||
|
||||
// Not used:
|
||||
// boolean isTheirOrderNewAssetPricing = theirOrderData.getTimestamp() >= BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
|
||||
// Determine their order price
|
||||
BigDecimal theirPrice;
|
||||
|
||||
if (isOurOrderNewPricing) {
|
||||
// Pricing units are the same way round for both orders, so no conversion needed.
|
||||
// Orders under 'old' pricing have been converted during repository update.
|
||||
theirPrice = theirOrderData.getPrice();
|
||||
LOGGER.trace(String.format("Their price: %s %s", theirPrice.toPlainString(), getPricePair()));
|
||||
} else {
|
||||
// If our order is 'old' pricing then all other existing orders must be 'old' pricing too
|
||||
// Their order pricing will be inverted, so convert
|
||||
theirPrice = BigDecimal.ONE.setScale(8).divide(theirOrderData.getPrice(), RoundingMode.DOWN);
|
||||
LOGGER.trace(String.format("Their price: %s %s per %s", theirPrice.toPlainString(), wantAssetData.getName(), haveAssetData.getName()));
|
||||
}
|
||||
// Pricing units are the same way round for both orders, so no conversion needed.
|
||||
theirPrice = theirOrderData.getPrice();
|
||||
LOGGER.trace(String.format("Their price: %s %s", theirPrice.toPlainString(), getPricePair()));
|
||||
|
||||
// If their price is worse than what we're willing to accept then we're done as prices only get worse as we iterate through list of orders
|
||||
if (isOurOrderNewPricing) {
|
||||
if (haveAssetId < wantAssetId && theirPrice.compareTo(ourPrice) > 0)
|
||||
break;
|
||||
if (haveAssetId > wantAssetId && theirPrice.compareTo(ourPrice) < 0)
|
||||
break;
|
||||
} else {
|
||||
// 'old' pricing scheme
|
||||
if (theirPrice.compareTo(ourPrice) < 0)
|
||||
break;
|
||||
}
|
||||
if (haveAssetId < wantAssetId && theirPrice.compareTo(ourPrice) > 0)
|
||||
break;
|
||||
if (haveAssetId > wantAssetId && theirPrice.compareTo(ourPrice) < 0)
|
||||
break;
|
||||
|
||||
// Calculate how much we could buy at their price.
|
||||
BigDecimal ourMaxAmount;
|
||||
if (isOurOrderNewPricing)
|
||||
// In 'new' pricing scheme, "amount" is expressed in terms of asset with highest assetID
|
||||
ourMaxAmount = this.getAmountLeft();
|
||||
else
|
||||
// In 'old' pricing scheme, "amount" is expressed in terms of our want-asset.
|
||||
ourMaxAmount = this.getAmountLeft().multiply(theirPrice).setScale(8, RoundingMode.DOWN);
|
||||
// Calculate how much we could buy at their price, "amount" is expressed in terms of asset with highest assetID.
|
||||
BigDecimal ourMaxAmount = this.getAmountLeft();
|
||||
LOGGER.trace("ourMaxAmount (max we could trade at their price): " + ourMaxAmount.stripTrailingZeros().toPlainString() + " " + matchingAssetData.getName());
|
||||
|
||||
// How much is remaining available in their order.
|
||||
@ -421,11 +365,11 @@ public class Order {
|
||||
throw new DataException(message);
|
||||
}
|
||||
|
||||
BigDecimal tradedWantAmount = (isOurOrderNewPricing && haveAssetId > wantAssetId) ? returnAmountTraded : matchedAmount;
|
||||
BigDecimal tradedHaveAmount = (isOurOrderNewPricing && haveAssetId > wantAssetId) ? matchedAmount : returnAmountTraded;
|
||||
BigDecimal tradedWantAmount = (haveAssetId > wantAssetId) ? returnAmountTraded : matchedAmount;
|
||||
BigDecimal tradedHaveAmount = (haveAssetId > wantAssetId) ? matchedAmount : returnAmountTraded;
|
||||
|
||||
// We also need to know how much have-asset to refund based on price improvement ('new' pricing only and only one direction applies)
|
||||
BigDecimal haveAssetRefund = isOurOrderNewPricing && haveAssetId < wantAssetId ? ourPrice.subtract(theirPrice).abs().multiply(matchedAmount).setScale(8, RoundingMode.DOWN) : BigDecimal.ZERO;
|
||||
// We also need to know how much have-asset to refund based on price improvement (only one direction applies)
|
||||
BigDecimal haveAssetRefund = haveAssetId < wantAssetId ? ourPrice.subtract(theirPrice).abs().multiply(matchedAmount).setScale(8, RoundingMode.DOWN) : BigDecimal.ZERO;
|
||||
|
||||
LOGGER.trace(String.format("We traded %s %s (have-asset) for %s %s (want-asset), saving %s %s (have-asset)",
|
||||
tradedHaveAmount.toPlainString(), haveAssetData.getName(),
|
||||
@ -440,7 +384,7 @@ public class Order {
|
||||
trade.process();
|
||||
|
||||
// Update our order in terms of fulfilment, etc. but do not save into repository as that's handled by Trade above
|
||||
BigDecimal amountFulfilled = isOurOrderNewPricing ? matchedAmount : returnAmountTraded;
|
||||
BigDecimal amountFulfilled = matchedAmount;
|
||||
this.orderData.setFulfilled(this.orderData.getFulfilled().add(amountFulfilled));
|
||||
LOGGER.trace("Updated our order's fulfilled amount to: " + this.orderData.getFulfilled().stripTrailingZeros().toPlainString() + " " + matchingAssetData.getName());
|
||||
LOGGER.trace("Our order's amount remaining: " + this.getAmountLeft().stripTrailingZeros().toPlainString() + " " + matchingAssetData.getName());
|
||||
|
@ -4,7 +4,6 @@ import java.math.BigDecimal;
|
||||
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.asset.OrderData;
|
||||
import org.qortal.data.asset.TradeData;
|
||||
import org.qortal.repository.AssetRepository;
|
||||
@ -17,12 +16,11 @@ public class Trade {
|
||||
private Repository repository;
|
||||
private TradeData tradeData;
|
||||
|
||||
private boolean isNewPricing;
|
||||
private AssetRepository assetRepository;
|
||||
|
||||
private OrderData initiatingOrder;
|
||||
private OrderData targetOrder;
|
||||
private BigDecimal newPricingFulfilled;
|
||||
private BigDecimal fulfilled;
|
||||
|
||||
// Constructors
|
||||
|
||||
@ -30,7 +28,6 @@ public class Trade {
|
||||
this.repository = repository;
|
||||
this.tradeData = tradeData;
|
||||
|
||||
this.isNewPricing = this.tradeData.getTimestamp() > BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
this.assetRepository = this.repository.getAssetRepository();
|
||||
}
|
||||
|
||||
@ -43,9 +40,9 @@ public class Trade {
|
||||
// Note: targetAmount is amount traded FROM target order
|
||||
// Note: initiatorAmount is amount traded FROM initiating order
|
||||
|
||||
// Under 'new' pricing scheme, "amount" and "fulfilled" are the same asset for both orders
|
||||
// "amount" and "fulfilled" are the same asset for both orders
|
||||
// which is the matchedAmount in asset with highest assetID
|
||||
this.newPricingFulfilled = (initiatingOrder.getHaveAssetId() < initiatingOrder.getWantAssetId()) ? this.tradeData.getTargetAmount() : this.tradeData.getInitiatorAmount();
|
||||
this.fulfilled = (initiatingOrder.getHaveAssetId() < initiatingOrder.getWantAssetId()) ? this.tradeData.getTargetAmount() : this.tradeData.getInitiatorAmount();
|
||||
}
|
||||
|
||||
public void process() throws DataException {
|
||||
@ -55,16 +52,16 @@ public class Trade {
|
||||
// Note: targetAmount is amount traded FROM target order
|
||||
// Note: initiatorAmount is amount traded FROM initiating order
|
||||
|
||||
// Update corresponding Orders on both sides of trade
|
||||
commonPrep();
|
||||
|
||||
initiatingOrder.setFulfilled(initiatingOrder.getFulfilled().add(isNewPricing ? newPricingFulfilled : tradeData.getInitiatorAmount()));
|
||||
// Update corresponding Orders on both sides of trade
|
||||
initiatingOrder.setFulfilled(initiatingOrder.getFulfilled().add(fulfilled));
|
||||
initiatingOrder.setIsFulfilled(Order.isFulfilled(initiatingOrder));
|
||||
// Set isClosed to true if isFulfilled now true
|
||||
initiatingOrder.setIsClosed(initiatingOrder.getIsFulfilled());
|
||||
assetRepository.save(initiatingOrder);
|
||||
|
||||
targetOrder.setFulfilled(targetOrder.getFulfilled().add(isNewPricing ? newPricingFulfilled : tradeData.getTargetAmount()));
|
||||
targetOrder.setFulfilled(targetOrder.getFulfilled().add(fulfilled));
|
||||
targetOrder.setIsFulfilled(Order.isFulfilled(targetOrder));
|
||||
// Set isClosed to true if isFulfilled now true
|
||||
targetOrder.setIsClosed(targetOrder.getIsFulfilled());
|
||||
@ -89,16 +86,16 @@ public class Trade {
|
||||
// Note: targetAmount is amount traded FROM target order
|
||||
// Note: initiatorAmount is amount traded FROM initiating order
|
||||
|
||||
// Revert corresponding Orders on both sides of trade
|
||||
commonPrep();
|
||||
|
||||
initiatingOrder.setFulfilled(initiatingOrder.getFulfilled().subtract(isNewPricing ? newPricingFulfilled : tradeData.getInitiatorAmount()));
|
||||
// Revert corresponding Orders on both sides of trade
|
||||
initiatingOrder.setFulfilled(initiatingOrder.getFulfilled().subtract(fulfilled));
|
||||
initiatingOrder.setIsFulfilled(Order.isFulfilled(initiatingOrder));
|
||||
// Set isClosed to false if isFulfilled now false
|
||||
initiatingOrder.setIsClosed(initiatingOrder.getIsFulfilled());
|
||||
assetRepository.save(initiatingOrder);
|
||||
|
||||
targetOrder.setFulfilled(targetOrder.getFulfilled().subtract(isNewPricing ? newPricingFulfilled : tradeData.getTargetAmount()));
|
||||
targetOrder.setFulfilled(targetOrder.getFulfilled().subtract(fulfilled));
|
||||
targetOrder.setIsFulfilled(Order.isFulfilled(targetOrder));
|
||||
// Set isClosed to false if isFulfilled now false
|
||||
targetOrder.setIsClosed(targetOrder.getIsFulfilled());
|
||||
|
@ -1,11 +1,9 @@
|
||||
package org.qortal.at;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.ciyam.at.MachineState;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.at.ATData;
|
||||
import org.qortal.data.at.ATStateData;
|
||||
@ -42,66 +40,18 @@ public class AT {
|
||||
int height = this.repository.getBlockRepository().getBlockchainHeight() + 1;
|
||||
byte[] creatorPublicKey = deployATTransactionData.getCreatorPublicKey();
|
||||
long creation = deployATTransactionData.getTimestamp();
|
||||
|
||||
byte[] creationBytes = deployATTransactionData.getCreationBytes();
|
||||
long assetId = deployATTransactionData.getAssetId();
|
||||
short version = (short) ((creationBytes[0] & 0xff) | (creationBytes[1] << 8)); // Little-endian
|
||||
|
||||
if (version >= 2) {
|
||||
MachineState machineState = new MachineState(deployATTransactionData.getCreationBytes());
|
||||
MachineState machineState = new MachineState(deployATTransactionData.getCreationBytes());
|
||||
|
||||
this.atData = new ATData(atAddress, creatorPublicKey, creation, machineState.version, assetId, machineState.getCodeBytes(),
|
||||
machineState.getIsSleeping(), machineState.getSleepUntilHeight(), machineState.getIsFinished(), machineState.getHadFatalError(),
|
||||
machineState.getIsFrozen(), machineState.getFrozenBalance());
|
||||
this.atData = new ATData(atAddress, creatorPublicKey, creation, machineState.version, assetId, machineState.getCodeBytes(),
|
||||
machineState.getIsSleeping(), machineState.getSleepUntilHeight(), machineState.getIsFinished(), machineState.getHadFatalError(),
|
||||
machineState.getIsFrozen(), machineState.getFrozenBalance());
|
||||
|
||||
byte[] stateData = machineState.toBytes();
|
||||
byte[] stateHash = Crypto.digest(stateData);
|
||||
byte[] stateData = machineState.toBytes();
|
||||
byte[] stateHash = Crypto.digest(stateData);
|
||||
|
||||
this.atStateData = new ATStateData(atAddress, height, creation, stateData, stateHash, BigDecimal.ZERO.setScale(8));
|
||||
} else {
|
||||
// Legacy v1 AT
|
||||
// We would deploy these in 'dead' state as they will never be run on Qortal
|
||||
// but this breaks import from Qora1 so something else will have to mark them dead at hard-fork
|
||||
|
||||
// Extract code bytes length
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(deployATTransactionData.getCreationBytes());
|
||||
|
||||
// v1 AT header is: version, reserved, code-pages, data-pages, call-stack-pages, user-stack-pages (all shorts)
|
||||
|
||||
// Number of code pages
|
||||
short numCodePages = byteBuffer.get(2 + 2);
|
||||
|
||||
// Skip header and also "minimum activation amount" (long)
|
||||
byteBuffer.position(6 * 2 + 8);
|
||||
|
||||
int codeLen = 0;
|
||||
|
||||
// Extract actual code length, stored in minimal-size form (byte, short or int)
|
||||
if (numCodePages * 256 < 257) {
|
||||
codeLen = byteBuffer.get() & 0xff;
|
||||
} else if (numCodePages * 256 < Short.MAX_VALUE + 1) {
|
||||
codeLen = byteBuffer.getShort() & 0xffff;
|
||||
} else if (numCodePages * 256 <= Integer.MAX_VALUE) {
|
||||
codeLen = byteBuffer.getInt();
|
||||
}
|
||||
|
||||
// Extract code bytes
|
||||
byte[] codeBytes = new byte[codeLen];
|
||||
byteBuffer.get(codeBytes);
|
||||
|
||||
// Create AT
|
||||
boolean isSleeping = false;
|
||||
Integer sleepUntilHeight = null;
|
||||
boolean isFinished = false;
|
||||
boolean hadFatalError = false;
|
||||
boolean isFrozen = false;
|
||||
Long frozenBalance = null;
|
||||
|
||||
this.atData = new ATData(atAddress, creatorPublicKey, creation, version, Asset.QORT, codeBytes, isSleeping, sleepUntilHeight, isFinished,
|
||||
hadFatalError, isFrozen, frozenBalance);
|
||||
|
||||
this.atStateData = new ATStateData(atAddress, height, creation, null, null, BigDecimal.ZERO.setScale(8));
|
||||
}
|
||||
this.atStateData = new ATStateData(atAddress, height, creation, stateData, stateHash, BigDecimal.ZERO.setScale(8));
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
@ -116,9 +66,7 @@ public class AT {
|
||||
ATRepository atRepository = this.repository.getATRepository();
|
||||
atRepository.save(this.atData);
|
||||
|
||||
// For version 2+ we also store initial AT state data
|
||||
if (this.atData.getVersion() >= 2)
|
||||
atRepository.save(this.atStateData);
|
||||
atRepository.save(this.atStateData);
|
||||
}
|
||||
|
||||
public void undeploy() throws DataException {
|
||||
|
@ -473,6 +473,9 @@ public class Block {
|
||||
|
||||
/**
|
||||
* Return the next block's version.
|
||||
* <p>
|
||||
* We're starting with version 4 as a nod to being newer than successor Qora,
|
||||
* whose latest block version was 3.
|
||||
*
|
||||
* @return 1, 2, 3 or 4
|
||||
*/
|
||||
@ -480,14 +483,7 @@ public class Block {
|
||||
if (this.blockData.getHeight() == null)
|
||||
throw new IllegalStateException("Can't determine next block's version as this block has no height set");
|
||||
|
||||
if (this.blockData.getHeight() < BlockChain.getInstance().getATReleaseHeight())
|
||||
return 1;
|
||||
else if (this.blockData.getTimestamp() < BlockChain.getInstance().getPowFixReleaseTimestamp())
|
||||
return 2;
|
||||
else if (this.blockData.getTimestamp() < BlockChain.getInstance().getQortalTimestamp())
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,15 +71,6 @@ public class BlockChain {
|
||||
private GenesisBlock.GenesisInfo genesisInfo;
|
||||
|
||||
public enum FeatureTrigger {
|
||||
messageHeight, // block height when MESSAGE transactions are enabled
|
||||
atHeight, // block height when CIYAM automated transactions are enabled
|
||||
assetsTimestamp, // timestamp when assets (issue/transfer/payments) are enabled
|
||||
votingTimestamp, // timestamp when voting is enabled
|
||||
arbitraryTimestamp, // timestamp when arbitrary transactions are enabled
|
||||
powfixTimestamp, // timestamp when various legacy fixes come into effect
|
||||
qortalTimestamp, // timestamp when Qortal changes come into effect
|
||||
newAssetPricingTimestamp, // timestamp when new asset pricing comes into effect
|
||||
groupApprovalTimestamp; // timestamp when transaction approval comes into effect
|
||||
}
|
||||
|
||||
/** Map of which blockchain features are enabled when (height/timestamp) */
|
||||
@ -357,42 +348,6 @@ public class BlockChain {
|
||||
|
||||
// Convenience methods for specific blockchain feature triggers
|
||||
|
||||
public long getMessageReleaseHeight() {
|
||||
return featureTriggers.get("messageHeight");
|
||||
}
|
||||
|
||||
public long getATReleaseHeight() {
|
||||
return featureTriggers.get("atHeight");
|
||||
}
|
||||
|
||||
public long getPowFixReleaseTimestamp() {
|
||||
return featureTriggers.get("powfixTimestamp");
|
||||
}
|
||||
|
||||
public long getAssetsReleaseTimestamp() {
|
||||
return featureTriggers.get("assetsTimestamp");
|
||||
}
|
||||
|
||||
public long getVotingReleaseTimestamp() {
|
||||
return featureTriggers.get("votingTimestamp");
|
||||
}
|
||||
|
||||
public long getArbitraryReleaseTimestamp() {
|
||||
return featureTriggers.get("arbitraryTimestamp");
|
||||
}
|
||||
|
||||
public long getQortalTimestamp() {
|
||||
return featureTriggers.get("qortalTimestamp");
|
||||
}
|
||||
|
||||
public long getNewAssetPricingTimestamp() {
|
||||
return featureTriggers.get("newAssetPricingTimestamp");
|
||||
}
|
||||
|
||||
public long getGroupApprovalTimestamp() {
|
||||
return featureTriggers.get("groupApprovalTimestamp");
|
||||
}
|
||||
|
||||
// More complex getters for aspects that change by height or timestamp
|
||||
|
||||
public BigDecimal getRewardAtHeight(int ourHeight) {
|
||||
|
@ -7,7 +7,6 @@ import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.transaction.Transaction.TransactionType;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@ -54,25 +53,16 @@ public class CreateAssetOrderTransactionData extends TransactionData {
|
||||
|
||||
// Called before converting to JSON for API
|
||||
public void beforeMarshal(Marshaller m) {
|
||||
final boolean isNewPricing = this.timestamp > BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
|
||||
this.amountAssetId = (isNewPricing && this.haveAssetId < this.wantAssetId) ? this.wantAssetId : this.haveAssetId;
|
||||
this.amountAssetId = Math.max(this.haveAssetId, this.wantAssetId);
|
||||
|
||||
// If we don't have the extra asset name fields then we can't fill in the others
|
||||
if (this.haveAssetName == null)
|
||||
return;
|
||||
|
||||
if (isNewPricing) {
|
||||
// 'new' pricing scheme
|
||||
if (this.haveAssetId < this.wantAssetId) {
|
||||
this.amountAssetName = this.wantAssetName;
|
||||
this.pricePair = this.haveAssetName + "/" + this.wantAssetName;
|
||||
} else {
|
||||
this.amountAssetName = this.haveAssetName;
|
||||
this.pricePair = this.wantAssetName + "/" + this.haveAssetName;
|
||||
}
|
||||
if (this.haveAssetId < this.wantAssetId) {
|
||||
this.amountAssetName = this.wantAssetName;
|
||||
this.pricePair = this.haveAssetName + "/" + this.wantAssetName;
|
||||
} else {
|
||||
// 'old' pricing scheme is simpler
|
||||
this.amountAssetName = this.haveAssetName;
|
||||
this.pricePair = this.wantAssetName + "/" + this.haveAssetName;
|
||||
}
|
||||
|
@ -677,12 +677,12 @@ public class HSQLDBDatabaseUpdates {
|
||||
stmt.execute("SET TIME ZONE INTERVAL '0:00' HOUR TO MINUTE");
|
||||
// Normalize amount/fulfilled to asset with highest assetID, BEFORE price correction
|
||||
stmt.execute("UPDATE AssetOrders SET amount = amount * price, fulfilled = fulfilled * price "
|
||||
+ "WHERE ordered < timestamp(" + BlockChain.getInstance().getNewAssetPricingTimestamp() + ") "
|
||||
+ "WHERE ordered < timestamp(" + 0 /* was BlockChain.getInstance().getNewAssetPricingTimestamp() */ + ") "
|
||||
+ "AND have_asset_id < want_asset_id");
|
||||
// Normalize price into lowest-assetID/highest-assetID price-pair, e.g. QORT/asset100
|
||||
// Note: HSQLDB uses BigDecimal's dividend.divide(divisor, RoundingMode.DOWN) too
|
||||
stmt.execute("UPDATE AssetOrders SET price = CAST(1 AS QortalAmount) / price "
|
||||
+ "WHERE ordered < timestamp(" + BlockChain.getInstance().getNewAssetPricingTimestamp() + ") "
|
||||
+ "WHERE ordered < timestamp(" + 0 /* was BlockChain.getInstance().getNewAssetPricingTimestamp() */ + ") "
|
||||
+ "AND have_asset_id < want_asset_id");
|
||||
// Revert time zone change above
|
||||
stmt.execute("SET TIME ZONE LOCAL");
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -91,13 +90,6 @@ public class ArbitraryTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are arbitrary transactions even allowed at this point?
|
||||
if (arbitraryTransactionData.getVersion() != Transaction.getVersionByTimestamp(arbitraryTransactionData.getTimestamp()))
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
if (this.arbitraryTransactionData.getTimestamp() < BlockChain.getInstance().getArbitraryReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check data length
|
||||
if (arbitraryTransactionData.getData().length < 1 || arbitraryTransactionData.getData().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
@ -8,7 +8,6 @@ import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.asset.Order;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.asset.AssetData;
|
||||
import org.qortal.data.asset.OrderData;
|
||||
import org.qortal.data.transaction.CreateAssetOrderTransactionData;
|
||||
@ -106,42 +105,27 @@ public class CreateAssetOrderTransaction extends Transaction {
|
||||
|
||||
Account creator = getCreator();
|
||||
|
||||
boolean isNewPricing = createOrderTransactionData.getTimestamp() >= BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
|
||||
BigDecimal committedCost;
|
||||
BigDecimal maxOtherAmount;
|
||||
|
||||
if (isNewPricing) {
|
||||
/*
|
||||
* This is different under "new" pricing scheme as "amount" might be either have-asset or want-asset,
|
||||
* whichever has the highest assetID.
|
||||
*
|
||||
* e.g. with assetID 11 "GOLD":
|
||||
* haveAssetId: 0 (QORT), wantAssetId: 11 (GOLD), amount: 123 (GOLD), price: 400 (QORT/GOLD)
|
||||
* stake 49200 QORT, return 123 GOLD
|
||||
*
|
||||
* haveAssetId: 11 (GOLD), wantAssetId: 0 (QORT), amount: 123 (GOLD), price: 400 (QORT/GOLD)
|
||||
* stake 123 GOLD, return 49200 QORT
|
||||
*/
|
||||
boolean isAmountWantAsset = haveAssetId < wantAssetId;
|
||||
/*
|
||||
* "amount" might be either have-asset or want-asset, whichever has the highest assetID.
|
||||
*
|
||||
* e.g. with assetID 11 "GOLD":
|
||||
* haveAssetId: 0 (QORT), wantAssetId: 11 (GOLD), amount: 123 (GOLD), price: 400 (QORT/GOLD)
|
||||
* stake 49200 QORT, return 123 GOLD
|
||||
*
|
||||
* haveAssetId: 11 (GOLD), wantAssetId: 0 (QORT), amount: 123 (GOLD), price: 400 (QORT/GOLD)
|
||||
* stake 123 GOLD, return 49200 QORT
|
||||
*/
|
||||
boolean isAmountWantAsset = haveAssetId < wantAssetId;
|
||||
|
||||
if (isAmountWantAsset) {
|
||||
// have/commit 49200 QORT, want/return 123 GOLD
|
||||
committedCost = createOrderTransactionData.getAmount().multiply(createOrderTransactionData.getPrice());
|
||||
maxOtherAmount = createOrderTransactionData.getAmount();
|
||||
} else {
|
||||
// have/commit 123 GOLD, want/return 49200 QORT
|
||||
committedCost = createOrderTransactionData.getAmount();
|
||||
maxOtherAmount = createOrderTransactionData.getAmount().multiply(createOrderTransactionData.getPrice());
|
||||
}
|
||||
if (isAmountWantAsset) {
|
||||
// have/commit 49200 QORT, want/return 123 GOLD
|
||||
committedCost = createOrderTransactionData.getAmount().multiply(createOrderTransactionData.getPrice());
|
||||
maxOtherAmount = createOrderTransactionData.getAmount();
|
||||
} else {
|
||||
/*
|
||||
* Under "old" pricing scheme, "amount" is always have-asset and price is always want-per-have.
|
||||
*
|
||||
* e.g. with assetID 11 "GOLD":
|
||||
* haveAssetId: 0 (QORT), wantAssetId: 11 (GOLD), amount: 49200 (QORT), price: 0.00250000 (GOLD/QORT)
|
||||
* haveAssetId: 11 (GOLD), wantAssetId: 0 (QORT), amount: 123 (GOLD), price: 400 (QORT/GOLD)
|
||||
*/
|
||||
// have/commit 123 GOLD, want/return 49200 QORT
|
||||
committedCost = createOrderTransactionData.getAmount();
|
||||
maxOtherAmount = createOrderTransactionData.getAmount().multiply(createOrderTransactionData.getPrice());
|
||||
}
|
||||
@ -166,9 +150,7 @@ public class CreateAssetOrderTransaction extends Transaction {
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
// Check creator has enough funds for fee in QORT
|
||||
// NOTE: in Gen1 pre-POWFIX-RELEASE transactions didn't have this check
|
||||
if (createOrderTransactionData.getTimestamp() >= BlockChain.getInstance().getPowFixReleaseTimestamp()
|
||||
&& creator.getConfirmedBalance(Asset.QORT).compareTo(createOrderTransactionData.getFee()) < 0)
|
||||
if (creator.getConfirmedBalance(Asset.QORT).compareTo(createOrderTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.transaction.CreatePollTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -78,11 +77,6 @@ public class CreatePollTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are CreatePollTransactions even allowed at this point?
|
||||
// In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used
|
||||
if (this.createPollTransactionData.getTimestamp() < BlockChain.getInstance().getVotingReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check owner address is valid
|
||||
if (!Crypto.isValidAddress(createPollTransactionData.getOwner()))
|
||||
return ValidationResult.INVALID_ADDRESS;
|
||||
|
@ -11,7 +11,6 @@ import org.ciyam.at.MachineState;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.at.AT;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.asset.AssetData;
|
||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||
@ -124,9 +123,6 @@ public class DeployAtTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
if (this.repository.getBlockRepository().getBlockchainHeight() < BlockChain.getInstance().getATReleaseHeight())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check name size bounds
|
||||
int nameLength = Utf8.encodedLength(deployATTransactionData.getName());
|
||||
if (nameLength < 1 || nameLength > MAX_NAME_SIZE)
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.transaction.IssueAssetTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -76,23 +75,11 @@ public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are IssueAssetTransactions even allowed at this point?
|
||||
// In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used
|
||||
if (this.issueAssetTransactionData.getTimestamp() < BlockChain.getInstance().getAssetsReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// "data" field is only allowed in v2
|
||||
// Check data field
|
||||
String data = this.issueAssetTransactionData.getData();
|
||||
if (this.issueAssetTransactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp()) {
|
||||
// v2 so check data field properly
|
||||
int dataLength = Utf8.encodedLength(data);
|
||||
if (data == null || dataLength < 1 || dataLength > Asset.MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
} else {
|
||||
// pre-v2 so disallow data field
|
||||
if (data != null && !data.isEmpty())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
}
|
||||
int dataLength = Utf8.encodedLength(data);
|
||||
if (data == null || dataLength < 1 || dataLength > Asset.MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
||||
// Check owner address is valid
|
||||
if (!Crypto.isValidAddress(issueAssetTransactionData.getOwner()))
|
||||
@ -128,10 +115,9 @@ public class IssueAssetTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isProcessable() throws DataException {
|
||||
// Check the asset name isn't already taken. This check is not present in gen1.
|
||||
if (issueAssetTransactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
if (this.repository.getAssetRepository().assetExists(issueAssetTransactionData.getAssetName()))
|
||||
return ValidationResult.ASSET_ALREADY_EXISTS;
|
||||
// Check the asset name isn't already taken.
|
||||
if (this.repository.getAssetRepository().assetExists(issueAssetTransactionData.getAssetName()))
|
||||
return ValidationResult.ASSET_ALREADY_EXISTS;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -89,13 +88,6 @@ public class MessageTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are message transactions even allowed at this point?
|
||||
if (messageTransactionData.getVersion() != Transaction.getVersionByTimestamp(messageTransactionData.getTimestamp()))
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
if (this.repository.getBlockRepository().getBlockchainHeight() < BlockChain.getInstance().getMessageReleaseHeight())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check data length
|
||||
if (messageTransactionData.getData().length < 1 || messageTransactionData.getData().length > MAX_DATA_SIZE)
|
||||
return ValidationResult.INVALID_DATA_LENGTH;
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.MultiPaymentTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -90,10 +89,6 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
public ValidationResult isValid() throws DataException {
|
||||
List<PaymentData> payments = multiPaymentTransactionData.getPayments();
|
||||
|
||||
// Are MultiPaymentTransactions even allowed at this point?
|
||||
if (this.multiPaymentTransactionData.getTimestamp() < BlockChain.getInstance().getAssetsReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check number of payments
|
||||
if (payments.isEmpty() || payments.size() > MAX_PAYMENTS_COUNT)
|
||||
return ValidationResult.INVALID_PAYMENTS_COUNT;
|
||||
@ -102,9 +97,7 @@ public class MultiPaymentTransaction extends Transaction {
|
||||
Account sender = getSender();
|
||||
|
||||
// Check sender has enough funds for fee
|
||||
// NOTE: in Gen1 pre-POWFIX-RELEASE transactions didn't have this check
|
||||
if (multiPaymentTransactionData.getTimestamp() >= BlockChain.getInstance().getPowFixReleaseTimestamp()
|
||||
&& sender.getConfirmedBalance(Asset.QORT).compareTo(multiPaymentTransactionData.getFee()) < 0)
|
||||
if (sender.getConfirmedBalance(Asset.QORT).compareTo(multiPaymentTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return new Payment(this.repository).isValid(multiPaymentTransactionData.getSenderPublicKey(), payments, multiPaymentTransactionData.getFee());
|
||||
|
@ -354,18 +354,15 @@ public abstract class Transaction {
|
||||
|
||||
/**
|
||||
* Return the transaction version number that should be used, based on passed timestamp.
|
||||
* <p>
|
||||
* We're starting with version 4 as a nod to being newer than successor Qora,
|
||||
* whose latest transaction version was 3.
|
||||
*
|
||||
* @param timestamp
|
||||
* @return transaction version number, likely 1 or 3
|
||||
* @return transaction version number
|
||||
*/
|
||||
public static int getVersionByTimestamp(long timestamp) {
|
||||
if (timestamp < BlockChain.getInstance().getPowFixReleaseTimestamp()) {
|
||||
return 1;
|
||||
} else if (timestamp < BlockChain.getInstance().getQortalTimestamp()) {
|
||||
return 3;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -803,10 +800,6 @@ public abstract class Transaction {
|
||||
if (!this.transactionData.getType().needsApproval)
|
||||
return false;
|
||||
|
||||
// Is group-approval even in effect yet?
|
||||
if (this.transactionData.getTimestamp() < BlockChain.getInstance().getGroupApprovalTimestamp())
|
||||
return false;
|
||||
|
||||
int txGroupId = this.transactionData.getTxGroupId();
|
||||
|
||||
if (txGroupId == Group.NO_GROUP)
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.TransferAssetTransactionData;
|
||||
@ -83,11 +82,6 @@ public class TransferAssetTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are TransferAssetTransactions even allowed at this point?
|
||||
// In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used
|
||||
if (this.transferAssetTransactionData.getTimestamp() < BlockChain.getInstance().getAssetsReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Wrap asset transfer as a payment and delegate final payment checks to Payment class
|
||||
return new Payment(this.repository).isValid(transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), transferAssetTransactionData.getFee());
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import java.util.List;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.asset.AssetData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -75,10 +74,6 @@ public class UpdateAssetTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// V2-only transaction
|
||||
if (this.updateAssetTransactionData.getTimestamp() < BlockChain.getInstance().getQortalTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check asset actually exists
|
||||
AssetData assetData = this.repository.getAssetRepository().fromAssetId(updateAssetTransactionData.getAssetId());
|
||||
if (assetData == null)
|
||||
|
@ -9,7 +9,6 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.account.PublicKeyAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.VoteOnPollTransactionData;
|
||||
import org.qortal.data.voting.PollData;
|
||||
@ -69,11 +68,6 @@ public class VoteOnPollTransaction extends Transaction {
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
// Are VoteOnPollTransactions even allowed at this point?
|
||||
// In gen1 this used NTP.getTime() but surely the transaction's timestamp should be used
|
||||
if (this.voteOnPollTransactionData.getTimestamp() < BlockChain.getInstance().getVotingReleaseTimestamp())
|
||||
return ValidationResult.NOT_YET_RELEASED;
|
||||
|
||||
// Check name size bounds
|
||||
int pollNameLength = Utf8.encodedLength(voteOnPollTransactionData.getPollName());
|
||||
if (pollNameLength < 1 || pollNameLength > Poll.MAX_NAME_SIZE)
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.AccountFlagsTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -45,9 +44,7 @@ public class AccountFlagsTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.AccountLevelTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -40,9 +39,7 @@ public class AccountLevelTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.AddGroupAdminTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -41,9 +40,7 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,10 +5,8 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||
@ -32,7 +30,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
private static final int DATA_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int NUMBER_PAYMENTS_LENGTH = INT_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = SERVICE_LENGTH + DATA_SIZE_LENGTH;
|
||||
private static final int EXTRAS_LENGTH = SERVICE_LENGTH + DATA_TYPE_LENGTH + DATA_SIZE_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -43,14 +41,14 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
layout.add("transaction's groupID", TransformationType.INT);
|
||||
layout.add("reference", TransformationType.SIGNATURE);
|
||||
layout.add("sender's public key", TransformationType.PUBLIC_KEY);
|
||||
layout.add("number of payments (v3+)", TransformationType.INT);
|
||||
layout.add("number of payments", TransformationType.INT);
|
||||
|
||||
layout.add("* recipient", TransformationType.ADDRESS);
|
||||
layout.add("* asset ID of payment", TransformationType.LONG);
|
||||
layout.add("* payment amount", TransformationType.AMOUNT);
|
||||
|
||||
layout.add("service ID", TransformationType.INT);
|
||||
layout.add("is data raw? (v4+)", TransformationType.BOOLEAN);
|
||||
layout.add("is data raw?", TransformationType.BOOLEAN);
|
||||
layout.add("data length", TransformationType.INT);
|
||||
layout.add("data", TransformationType.DATA);
|
||||
layout.add("fee", TransformationType.AMOUNT);
|
||||
@ -62,9 +60,7 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int version = Transaction.getVersionByTimestamp(timestamp);
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -82,14 +78,10 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int service = byteBuffer.getInt();
|
||||
|
||||
// With V4+ we might be receiving hash of data instead of actual raw data
|
||||
DataType dataType = DataType.RAW_DATA;
|
||||
if (version >= 4) {
|
||||
boolean isRaw = byteBuffer.get() != 0;
|
||||
// We might be receiving hash of data instead of actual raw data
|
||||
boolean isRaw = byteBuffer.get() != 0;
|
||||
|
||||
if (!isRaw)
|
||||
dataType = DataType.DATA_HASH;
|
||||
}
|
||||
DataType dataType = isRaw ? DataType.RAW_DATA : DataType.DATA_HASH;
|
||||
|
||||
int dataSize = byteBuffer.getInt();
|
||||
// Don't allow invalid dataSize here to avoid run-time issues
|
||||
@ -114,13 +106,8 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int length = getBaseLength(transactionData) + EXTRAS_LENGTH + arbitraryTransactionData.getData().length;
|
||||
|
||||
// V4+ transactions have data type
|
||||
if (arbitraryTransactionData.getVersion() >= 4)
|
||||
length += DATA_TYPE_LENGTH;
|
||||
|
||||
// V3+ transactions have optional payments
|
||||
if (arbitraryTransactionData.getVersion() >= 3)
|
||||
length += NUMBER_PAYMENTS_LENGTH + arbitraryTransactionData.getPayments().size() * PaymentTransformer.getDataLength();
|
||||
// Optional payments
|
||||
length += NUMBER_PAYMENTS_LENGTH + arbitraryTransactionData.getPayments().size() * PaymentTransformer.getDataLength();
|
||||
|
||||
return length;
|
||||
}
|
||||
@ -133,19 +120,15 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
transformCommonBytes(transactionData, bytes);
|
||||
|
||||
if (arbitraryTransactionData.getVersion() != 1) {
|
||||
List<PaymentData> payments = arbitraryTransactionData.getPayments();
|
||||
bytes.write(Ints.toByteArray(payments.size()));
|
||||
List<PaymentData> payments = arbitraryTransactionData.getPayments();
|
||||
bytes.write(Ints.toByteArray(payments.size()));
|
||||
|
||||
for (PaymentData paymentData : payments)
|
||||
bytes.write(PaymentTransformer.toBytes(paymentData));
|
||||
}
|
||||
for (PaymentData paymentData : payments)
|
||||
bytes.write(PaymentTransformer.toBytes(paymentData));
|
||||
|
||||
bytes.write(Ints.toByteArray(arbitraryTransactionData.getService()));
|
||||
|
||||
// V4+ also has data type
|
||||
if (arbitraryTransactionData.getVersion() >= 4)
|
||||
bytes.write((byte) (arbitraryTransactionData.getDataType() == DataType.RAW_DATA ? 1 : 0));
|
||||
bytes.write((byte) (arbitraryTransactionData.getDataType() == DataType.RAW_DATA ? 1 : 0));
|
||||
|
||||
bytes.write(Ints.toByteArray(arbitraryTransactionData.getData().length));
|
||||
bytes.write(arbitraryTransactionData.getData());
|
||||
@ -162,38 +145,15 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification are really mangled so we need to test for v1-ness and adjust the bytes accordingly.
|
||||
* Signature for ArbitraryTransactions always uses hash of data, not raw data itself.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
protected static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
ArbitraryTransactionData arbitraryTransactionData = (ArbitraryTransactionData) transactionData;
|
||||
|
||||
// For v4, signature uses hash of data, not raw data itself
|
||||
if (arbitraryTransactionData.getVersion() == 4)
|
||||
return toBytesForSigningImplV4(arbitraryTransactionData);
|
||||
|
||||
byte[] bytes = TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
if (arbitraryTransactionData.getVersion() == 1 || transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return bytes;
|
||||
|
||||
// Special v1 version
|
||||
|
||||
// In v1, a coding error means that all bytes prior to final payment entry are lost!
|
||||
// If there are no payments then we can skip mangling
|
||||
if (arbitraryTransactionData.getPayments().isEmpty())
|
||||
return bytes;
|
||||
|
||||
// So we're left with: final payment entry, service, data size, data, fee
|
||||
int v1Length = PaymentTransformer.getDataLength() + SERVICE_LENGTH + DATA_SIZE_LENGTH + arbitraryTransactionData.getData().length + FEE_LENGTH;
|
||||
int v1Start = bytes.length - v1Length;
|
||||
|
||||
return Arrays.copyOfRange(bytes, v1Start, bytes.length);
|
||||
}
|
||||
|
||||
private static byte[] toBytesForSigningImplV4(ArbitraryTransactionData arbitraryTransactionData) throws TransformationException {
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
@ -210,6 +170,8 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(Ints.toByteArray(arbitraryTransactionData.getService()));
|
||||
|
||||
bytes.write(Ints.toByteArray(arbitraryTransactionData.getData().length));
|
||||
|
||||
// Signature uses hash of data, not raw data itself
|
||||
switch (arbitraryTransactionData.getDataType()) {
|
||||
case DATA_HASH:
|
||||
bytes.write(arbitraryTransactionData.getData());
|
||||
@ -228,7 +190,6 @@ public class ArbitraryTransactionTransformer extends TransactionTransformer {
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.BuyNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -45,9 +44,7 @@ public class BuyNameTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CancelAssetOrderTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -37,9 +36,7 @@ public class CancelAssetOrderTransactionTransformer extends TransactionTransform
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CancelGroupBanTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -41,9 +40,7 @@ public class CancelGroupBanTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CancelGroupInviteTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -41,9 +40,7 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CancelSellNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -41,9 +40,7 @@ public class CancelSellNameTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CreateAssetOrderTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -13,7 +12,6 @@ import org.qortal.transaction.Transaction.TransactionType;
|
||||
import org.qortal.transform.TransformationException;
|
||||
import org.qortal.utils.Serialization;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
public class CreateAssetOrderTransactionTransformer extends TransactionTransformer {
|
||||
@ -44,9 +42,7 @@ public class CreateAssetOrderTransactionTransformer extends TransactionTransform
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -102,41 +98,4 @@ public class CreateAssetOrderTransactionTransformer extends TransactionTransform
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification have mangled price so we need to test for v1-ness and adjust the bytes accordingly.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
// Special v1 version
|
||||
try {
|
||||
CreateAssetOrderTransactionData createOrderTransactionData = (CreateAssetOrderTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(createOrderTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(createOrderTransactionData.getTimestamp()));
|
||||
bytes.write(createOrderTransactionData.getReference());
|
||||
|
||||
bytes.write(createOrderTransactionData.getCreatorPublicKey());
|
||||
bytes.write(Longs.toByteArray(createOrderTransactionData.getHaveAssetId()));
|
||||
bytes.write(Longs.toByteArray(createOrderTransactionData.getWantAssetId()));
|
||||
Serialization.serializeBigDecimal(bytes, createOrderTransactionData.getAmount(), AMOUNT_LENGTH);
|
||||
|
||||
// This is the crucial difference
|
||||
Serialization.serializeBigDecimal(bytes, createOrderTransactionData.getPrice(), FEE_LENGTH);
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, createOrderTransactionData.getFee());
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CreateGroupTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -56,9 +55,7 @@ public class CreateGroupTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -7,7 +7,6 @@ import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CreatePollTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -54,9 +53,7 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -78,13 +75,6 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
String optionName = Serialization.deserializeSizedString(byteBuffer, Poll.MAX_NAME_SIZE);
|
||||
|
||||
pollOptions.add(new PollOptionData(optionName));
|
||||
|
||||
// V1 only: voter count also present
|
||||
if (timestamp < BlockChain.getInstance().getQortalTimestamp()) {
|
||||
int voterCount = byteBuffer.getInt();
|
||||
if (voterCount != 0)
|
||||
throw new TransformationException("Unexpected voter count in byte data for CreatePollTransaction");
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
@ -104,15 +94,10 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
+ Utf8.encodedLength(createPollTransactionData.getDescription());
|
||||
|
||||
// Add lengths for each poll options
|
||||
for (PollOptionData pollOptionData : createPollTransactionData.getPollOptions()) {
|
||||
for (PollOptionData pollOptionData : createPollTransactionData.getPollOptions())
|
||||
// option-string-length, option-string
|
||||
dataLength += INT_LENGTH + Utf8.encodedLength(pollOptionData.getOptionName());
|
||||
|
||||
if (transactionData.getTimestamp() < BlockChain.getInstance().getQortalTimestamp())
|
||||
// v1 only: voter-count (should always be zero)
|
||||
dataLength += INT_LENGTH;
|
||||
}
|
||||
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
@ -133,16 +118,9 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
List<PollOptionData> pollOptions = createPollTransactionData.getPollOptions();
|
||||
bytes.write(Ints.toByteArray(pollOptions.size()));
|
||||
|
||||
for (PollOptionData pollOptionData : pollOptions) {
|
||||
for (PollOptionData pollOptionData : pollOptions)
|
||||
Serialization.serializeSizedString(bytes, pollOptionData.getOptionName());
|
||||
|
||||
if (transactionData.getTimestamp() < BlockChain.getInstance().getQortalTimestamp()) {
|
||||
// In v1, CreatePollTransaction uses Poll.toBytes which serializes voters too.
|
||||
// Zero voters as this is a new poll.
|
||||
bytes.write(Ints.toByteArray(0));
|
||||
}
|
||||
}
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, createPollTransactionData.getFee());
|
||||
|
||||
if (createPollTransactionData.getSignature() != null)
|
||||
@ -154,26 +132,4 @@ public class CreatePollTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification have transaction type set to REGISTER_NAME_TRANSACTION so we need to test for v1-ness and adjust the bytes
|
||||
* accordingly.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
byte[] bytes = TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return bytes;
|
||||
|
||||
// Special v1 version
|
||||
|
||||
// Replace transaction type with incorrect Register Name value
|
||||
System.arraycopy(Ints.toByteArray(TransactionType.REGISTER_NAME.value), 0, bytes, 0, INT_LENGTH);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,13 +5,10 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.transaction.DeployAtTransaction;
|
||||
import org.qortal.transaction.Transaction;
|
||||
import org.qortal.transaction.Transaction.TransactionType;
|
||||
import org.qortal.transform.TransformationException;
|
||||
import org.qortal.utils.Serialization;
|
||||
@ -32,7 +29,7 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
private static final int ASSET_ID_LENGTH = LONG_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + AT_TYPE_SIZE_LENGTH + TAGS_SIZE_LENGTH + CREATION_BYTES_SIZE_LENGTH
|
||||
+ AMOUNT_LENGTH;
|
||||
+ AMOUNT_LENGTH + ASSET_ID_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -60,11 +57,7 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int version = Transaction.getVersionByTimestamp(timestamp);
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -88,9 +81,7 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
long assetId = Asset.QORT;
|
||||
if (version >= 4)
|
||||
assetId = byteBuffer.getLong();
|
||||
long assetId = byteBuffer.getLong();
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
@ -107,12 +98,6 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int dataLength = getBaseLength(transactionData) + EXTRAS_LENGTH;
|
||||
|
||||
int version = Transaction.getVersionByTimestamp(transactionData.getTimestamp());
|
||||
|
||||
// V4+ have assetId too
|
||||
if (version >= 4)
|
||||
dataLength += ASSET_ID_LENGTH;
|
||||
|
||||
dataLength += Utf8.encodedLength(deployATTransactionData.getName()) + Utf8.encodedLength(deployATTransactionData.getDescription())
|
||||
+ Utf8.encodedLength(deployATTransactionData.getAtType()) + Utf8.encodedLength(deployATTransactionData.getTags())
|
||||
+ deployATTransactionData.getCreationBytes().length;
|
||||
@ -124,8 +109,6 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
try {
|
||||
DeployAtTransactionData deployATTransactionData = (DeployAtTransactionData) transactionData;
|
||||
|
||||
int version = Transaction.getVersionByTimestamp(transactionData.getTimestamp());
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
transformCommonBytes(transactionData, bytes);
|
||||
@ -144,8 +127,7 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, deployATTransactionData.getAmount());
|
||||
|
||||
if (version >= 4)
|
||||
bytes.write(Longs.toByteArray(deployATTransactionData.getAssetId()));
|
||||
bytes.write(Longs.toByteArray(deployATTransactionData.getAssetId()));
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, deployATTransactionData.getFee());
|
||||
|
||||
@ -158,51 +140,4 @@ public class DeployAtTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification omit AT-type and tags so we need to test for v1-ness and adjust the bytes accordingly.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
// Special v1 version
|
||||
|
||||
// Easier to start from scratch
|
||||
try {
|
||||
DeployAtTransactionData deployATTransactionData = (DeployAtTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(deployATTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(deployATTransactionData.getTimestamp()));
|
||||
bytes.write(deployATTransactionData.getReference());
|
||||
|
||||
bytes.write(deployATTransactionData.getCreatorPublicKey());
|
||||
|
||||
Serialization.serializeSizedString(bytes, deployATTransactionData.getName());
|
||||
|
||||
Serialization.serializeSizedString(bytes, deployATTransactionData.getDescription());
|
||||
|
||||
// Omitted: Serialization.serializeSizedString(bytes, deployATTransactionData.getATType());
|
||||
|
||||
// Omitted: Serialization.serializeSizedString(bytes, deployATTransactionData.getTags());
|
||||
|
||||
byte[] creationBytes = deployATTransactionData.getCreationBytes();
|
||||
bytes.write(Ints.toByteArray(creationBytes.length));
|
||||
bytes.write(creationBytes);
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, deployATTransactionData.getAmount());
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, deployATTransactionData.getFee());
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.account.GenesisAccount;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.GenesisTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -28,6 +26,8 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
private static final int AMOUNT_LENGTH = LONG_LENGTH;
|
||||
private static final int ASSET_ID_LENGTH = LONG_LENGTH;
|
||||
|
||||
private static final int TOTAL_LENGTH = TYPE_LENGTH + TIMESTAMP_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH + ASSET_ID_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
static {
|
||||
@ -47,9 +47,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
long assetId = Asset.QORT;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
assetId = byteBuffer.getLong();
|
||||
long assetId = byteBuffer.getLong();
|
||||
|
||||
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, Group.NO_GROUP, null, GenesisAccount.PUBLIC_KEY, BigDecimal.ZERO, null);
|
||||
|
||||
@ -57,11 +55,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
if (transactionData.getTimestamp() < BlockChain.getInstance().getQortalTimestamp())
|
||||
return TYPE_LENGTH + TIMESTAMP_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH;
|
||||
|
||||
// Qortal
|
||||
return TYPE_LENGTH + TIMESTAMP_LENGTH + RECIPIENT_LENGTH + AMOUNT_LENGTH + ASSET_ID_LENGTH;
|
||||
return TOTAL_LENGTH;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
@ -78,8 +72,7 @@ public class GenesisTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, genesisTransactionData.getAmount());
|
||||
|
||||
if (genesisTransactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
bytes.write(Longs.toByteArray(genesisTransactionData.getAssetId()));
|
||||
bytes.write(Longs.toByteArray(genesisTransactionData.getAssetId()));
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.GroupApprovalTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -39,9 +38,7 @@ public class GroupApprovalTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.GroupBanTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -48,9 +47,7 @@ public class GroupBanTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.GroupInviteTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -43,9 +42,7 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.GroupKickTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -46,9 +45,7 @@ public class GroupKickTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -4,10 +4,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.IssueAssetTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -26,12 +24,11 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
private static final int DESCRIPTION_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int QUANTITY_LENGTH = LONG_LENGTH;
|
||||
private static final int IS_DIVISIBLE_LENGTH = BOOLEAN_LENGTH;
|
||||
private static final int ASSET_REFERENCE_LENGTH = REFERENCE_LENGTH;
|
||||
private static final int DATA_SIZE_LENGTH = INT_LENGTH;
|
||||
private static final int IS_UNSPENDABLE_LENGTH = BOOLEAN_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + QUANTITY_LENGTH
|
||||
+ IS_DIVISIBLE_LENGTH;
|
||||
+ IS_DIVISIBLE_LENGTH + DATA_SIZE_LENGTH + IS_UNSPENDABLE_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -59,9 +56,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -78,18 +73,9 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
boolean isDivisible = byteBuffer.get() != 0;
|
||||
|
||||
byte[] assetReference = new byte[ASSET_REFERENCE_LENGTH];
|
||||
String data = "";
|
||||
boolean isUnspendable = false;
|
||||
String data = Serialization.deserializeSizedString(byteBuffer, Asset.MAX_DATA_SIZE);
|
||||
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp()) {
|
||||
// in v2, assets have additional fields
|
||||
data = Serialization.deserializeSizedString(byteBuffer, Asset.MAX_DATA_SIZE);
|
||||
isUnspendable = byteBuffer.get() != 0;
|
||||
} else {
|
||||
// In v1, IssueAssetTransaction uses Asset.parse which also deserializes reference.
|
||||
byteBuffer.get(assetReference);
|
||||
}
|
||||
boolean isUnspendable = byteBuffer.get() != 0;
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
@ -104,19 +90,10 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
IssueAssetTransactionData issueAssetTransactionData = (IssueAssetTransactionData) transactionData;
|
||||
|
||||
int dataLength = getBaseLength(transactionData) + EXTRAS_LENGTH
|
||||
return getBaseLength(transactionData) + EXTRAS_LENGTH
|
||||
+ Utf8.encodedLength(issueAssetTransactionData.getAssetName())
|
||||
+ Utf8.encodedLength(issueAssetTransactionData.getDescription());
|
||||
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp()) {
|
||||
// In v2, assets have additional fields.
|
||||
dataLength += DATA_SIZE_LENGTH + Utf8.encodedLength(issueAssetTransactionData.getData()) + IS_UNSPENDABLE_LENGTH;
|
||||
} else {
|
||||
// In v1, IssueAssetTransaction uses Asset.toBytes which also serializes reference.
|
||||
dataLength += ASSET_REFERENCE_LENGTH;
|
||||
}
|
||||
|
||||
return dataLength;
|
||||
+ Utf8.encodedLength(issueAssetTransactionData.getDescription())
|
||||
+ Utf8.encodedLength(issueAssetTransactionData.getData());
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
@ -136,20 +113,9 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
bytes.write(Longs.toByteArray(issueAssetTransactionData.getQuantity()));
|
||||
bytes.write((byte) (issueAssetTransactionData.getIsDivisible() ? 1 : 0));
|
||||
|
||||
// In v2, assets have additional fields.
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp()) {
|
||||
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getData());
|
||||
bytes.write((byte) (issueAssetTransactionData.getIsUnspendable() ? 1 : 0));
|
||||
} else {
|
||||
// In v1, IssueAssetTransaction uses Asset.toBytes which also
|
||||
// serializes Asset's reference which is the IssueAssetTransaction's
|
||||
// signature
|
||||
byte[] assetReference = issueAssetTransactionData.getSignature();
|
||||
if (assetReference != null)
|
||||
bytes.write(assetReference);
|
||||
else
|
||||
bytes.write(new byte[ASSET_REFERENCE_LENGTH]);
|
||||
}
|
||||
Serialization.serializeSizedString(bytes, issueAssetTransactionData.getData());
|
||||
|
||||
bytes.write((byte) (issueAssetTransactionData.getIsUnspendable() ? 1 : 0));
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, issueAssetTransactionData.getFee());
|
||||
|
||||
@ -162,32 +128,4 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification have asset's reference zeroed
|
||||
* so we need to test for v1-ness and adjust the bytes accordingly.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
byte[] bytes = TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return bytes;
|
||||
|
||||
// Special v1 version
|
||||
|
||||
// Zero duplicate signature/reference
|
||||
int start = bytes.length - ASSET_REFERENCE_LENGTH - FEE_LENGTH; // before
|
||||
// asset
|
||||
// reference
|
||||
// (and
|
||||
// fee)
|
||||
int end = start + ASSET_REFERENCE_LENGTH;
|
||||
Arrays.fill(bytes, start, end, (byte) 0);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.JoinGroupTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -39,9 +38,7 @@ public class JoinGroupTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.LeaveGroupTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -39,9 +38,7 @@ public class LeaveGroupTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,8 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.MessageTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -29,7 +27,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
private static final int IS_TEXT_LENGTH = BOOLEAN_LENGTH;
|
||||
private static final int IS_ENCRYPTED_LENGTH = BOOLEAN_LENGTH;
|
||||
|
||||
private static final int EXTRAS_LENGTH = RECIPIENT_LENGTH + AMOUNT_LENGTH + DATA_SIZE_LENGTH + IS_ENCRYPTED_LENGTH + IS_TEXT_LENGTH;
|
||||
private static final int EXTRAS_LENGTH = RECIPIENT_LENGTH + ASSET_ID_LENGTH + AMOUNT_LENGTH + DATA_SIZE_LENGTH + IS_ENCRYPTED_LENGTH + IS_TEXT_LENGTH;
|
||||
|
||||
protected static final TransactionLayout layout;
|
||||
|
||||
@ -41,7 +39,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
layout.add("reference", TransformationType.SIGNATURE);
|
||||
layout.add("sender's public key", TransformationType.PUBLIC_KEY);
|
||||
layout.add("recipient", TransformationType.ADDRESS);
|
||||
layout.add("asset ID of payment (v2+)", TransformationType.LONG);
|
||||
layout.add("asset ID of payment", TransformationType.LONG);
|
||||
layout.add("payment (can be zero)", TransformationType.AMOUNT);
|
||||
layout.add("message length", TransformationType.INT);
|
||||
layout.add("message", TransformationType.DATA);
|
||||
@ -56,9 +54,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
int version = Transaction.getVersionByTimestamp(timestamp);
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -67,11 +63,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
String recipient = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
long assetId;
|
||||
if (version == 1)
|
||||
assetId = Asset.QORT;
|
||||
else
|
||||
assetId = byteBuffer.getLong();
|
||||
long assetId = byteBuffer.getLong();
|
||||
|
||||
BigDecimal amount = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
@ -100,13 +92,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
MessageTransactionData messageTransactionData = (MessageTransactionData) transactionData;
|
||||
|
||||
int dataLength = getBaseLength(transactionData) + EXTRAS_LENGTH + messageTransactionData.getData().length;
|
||||
|
||||
// V3+ has assetID for amount
|
||||
if (messageTransactionData.getVersion() != 1)
|
||||
dataLength += ASSET_ID_LENGTH;
|
||||
|
||||
return dataLength;
|
||||
return getBaseLength(transactionData) + EXTRAS_LENGTH + messageTransactionData.getData().length;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
@ -119,8 +105,7 @@ public class MessageTransactionTransformer extends TransactionTransformer {
|
||||
|
||||
Serialization.serializeAddress(bytes, messageTransactionData.getRecipient());
|
||||
|
||||
if (messageTransactionData.getVersion() != 1)
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAssetId()));
|
||||
bytes.write(Longs.toByteArray(messageTransactionData.getAssetId()));
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, messageTransactionData.getAmount());
|
||||
|
||||
|
@ -5,10 +5,8 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.MultiPaymentTransactionData;
|
||||
@ -47,9 +45,7 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
@ -103,27 +99,4 @@ public class MultiPaymentTransactionTransformer extends TransactionTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In Qora v1, the bytes used for verification are really mangled so we need to test for v1-ness and adjust the bytes accordingly.
|
||||
*
|
||||
* @param transactionData
|
||||
* @return byte[]
|
||||
* @throws TransformationException
|
||||
*/
|
||||
public static byte[] toBytesForSigningImpl(TransactionData transactionData) throws TransformationException {
|
||||
byte[] bytes = TransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
return bytes;
|
||||
|
||||
// Special v1 version
|
||||
|
||||
// In v1, a coding error means that all bytes prior to final payment entry are lost!
|
||||
// So we're left with: final payment entry and fee. Signature has already been stripped
|
||||
int v1Length = PaymentTransformer.getDataLength() + FEE_LENGTH;
|
||||
int v1Start = bytes.length - v1Length;
|
||||
|
||||
return Arrays.copyOfRange(bytes, v1Start, bytes.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.PaymentTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -39,9 +38,7 @@ public class PaymentTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.RegisterNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -46,9 +45,7 @@ public class RegisterNameTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.RemoveGroupAdminTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -41,9 +40,7 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.RewardShareTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -40,9 +39,7 @@ public class RewardShareTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.SellNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -43,9 +42,7 @@ public class SellNameTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.SetGroupTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
@ -39,9 +38,7 @@ public class SetGroupTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -18,7 +18,6 @@ import javax.xml.bind.annotation.XmlElement;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.account.PrivateKeyAccount;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.transaction.Transaction;
|
||||
import org.qortal.transaction.Transaction.TransactionType;
|
||||
@ -222,13 +221,8 @@ public abstract class TransactionTransformer extends Transformer {
|
||||
}
|
||||
|
||||
protected static int getBaseLength(TransactionData transactionData) {
|
||||
// All transactions have at least txType, timestamp, reference, tx creator's public key and also fee and signature (on the end)
|
||||
int baseLength = TYPE_LENGTH + TIMESTAMP_LENGTH + REFERENCE_LENGTH + PUBLIC_KEY_LENGTH + FEE_LENGTH + SIGNATURE_LENGTH;
|
||||
|
||||
if (transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp())
|
||||
baseLength += GROUPID_LENGTH;
|
||||
|
||||
return baseLength;
|
||||
// All transactions have at least txType, timestamp, txGroupId, reference, tx creator's public key and also fee and signature (on the end)
|
||||
return TYPE_LENGTH + TIMESTAMP_LENGTH + GROUPID_LENGTH + REFERENCE_LENGTH + PUBLIC_KEY_LENGTH + FEE_LENGTH + SIGNATURE_LENGTH;
|
||||
}
|
||||
|
||||
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||
@ -309,17 +303,14 @@ public abstract class TransactionTransformer extends Transformer {
|
||||
}
|
||||
|
||||
protected static void transformCommonBytes(TransactionData transactionData, ByteArrayOutputStream bytes) throws IOException {
|
||||
boolean v2 = transactionData.getTimestamp() >= BlockChain.getInstance().getQortalTimestamp();
|
||||
|
||||
// Transaction type
|
||||
bytes.write(Ints.toByteArray(transactionData.getType().value));
|
||||
|
||||
// Timestamp
|
||||
bytes.write(Longs.toByteArray(transactionData.getTimestamp()));
|
||||
|
||||
if (v2)
|
||||
// Transaction's groupID
|
||||
bytes.write(Ints.toByteArray(transactionData.getTxGroupId()));
|
||||
// Transaction's groupID
|
||||
bytes.write(Ints.toByteArray(transactionData.getTxGroupId()));
|
||||
|
||||
// Reference
|
||||
bytes.write(transactionData.getReference());
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.TransferAssetTransactionData;
|
||||
@ -43,9 +42,7 @@ public class TransferAssetTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.TransferPrivsTransactionData;
|
||||
@ -37,9 +36,7 @@ public class TransferPrivsTransactionTransformer extends TransactionTransformer
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -6,7 +6,6 @@ import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.UpdateAssetTransactionData;
|
||||
@ -50,9 +49,7 @@ public class UpdateAssetTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.UpdateGroupTransactionData;
|
||||
@ -56,9 +55,7 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.UpdateNameTransactionData;
|
||||
@ -46,9 +45,7 @@ public class UpdateNameTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.VoteOnPollTransactionData;
|
||||
@ -44,9 +43,7 @@ public class VoteOnPollTransactionTransformer extends TransactionTransformer {
|
||||
public static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
int txGroupId = 0;
|
||||
if (timestamp >= BlockChain.getInstance().getQortalTimestamp())
|
||||
txGroupId = byteBuffer.getInt();
|
||||
int txGroupId = byteBuffer.getInt();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
@ -1,78 +0,0 @@
|
||||
package org.qortal.test;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.test.common.Common;
|
||||
import org.qortal.transaction.CreateAssetOrderTransaction;
|
||||
import org.qortal.transaction.CreatePollTransaction;
|
||||
import org.qortal.transaction.IssueAssetTransaction;
|
||||
import org.qortal.transform.TransformationException;
|
||||
import org.qortal.transform.transaction.TransactionTransformer;
|
||||
import org.qortal.utils.NTP;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import com.google.common.hash.HashCode;
|
||||
|
||||
public class CompatibilityTests extends Common {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useSettings("test-settings-v1.json");
|
||||
NTP.setFixedOffset(Settings.getInstance().getTestNtpOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateOrderTransactionSignature() throws TransformationException {
|
||||
// 4EsGzQ87rXqXw2nic8LiihGCrM5iNErK53u9TRo2AJv4FWWyCK7bUKrCmswnrBbkB7Dsk7wfzi9hM2TGGqm6LVpd
|
||||
byte[] rawTx = HashCode
|
||||
.fromString("0000000d" + "000001489be3ef8e"
|
||||
+ "10b52b229c73afb40a56df4f1c9f65072041011cf9ae25a053397d9fc5578bc8f1412eb404de4e318e24302863fc52889eb848af65a6b17cfc964267388f5802"
|
||||
+ "bf497fa72ed16894f3acab6c4a101fd8b5fd42f0420dad45474388d5492d38d0" + "0000000000000000" + "0000000000000001"
|
||||
+ "000000000000000005f5e100" + "000000000000000005f5e100" + "0000000005f5e100"
|
||||
+ "a2025bfde5c90254e16150db6aef6189bb2856df51940b6a15b1d5f174451236062c982af4da3429941337abc7002a862782fb9c726bfc95aea31e30bf66a502")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
CreateAssetOrderTransaction transaction = new CreateAssetOrderTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePollTransactionSignature() throws TransformationException {
|
||||
// 5xo8YxDVTFVR1pdmtxYkRbq3PkcKVttyH7wCVAfgqokDMKE1XW6zrqFgJG8vRQz9qi5r8cqBoSgFKLnQRoSyzpgF
|
||||
byte[] rawTx = HashCode
|
||||
.fromString("00000008" + "00000146d4237f03"
|
||||
+ "c201817ee2d4363801b63cbe154f6796719feb5a9673758dfda7b5e616cddd1263bbb75ce6a14ca116abe2d34ea68f353379d0c0d48da62180677053792f3b00"
|
||||
+ "ef893a99782612754157d868fc4194577cca8ca5dd264c90855829f0e4bbec3a" + "3a91655f3c70d7a38980b449ccf7acd84de41f99dae6215ed5" + "0000000a"
|
||||
+ "746869736973706f6c6c" + "00000004" + "74657374" + "00000002" + "00000011" + "546869732069732073706f6e6765626f62" + "00000000"
|
||||
+ "0000000f" + "54686973206973207061747269636b" + "00000000" + "0000000005f5e100"
|
||||
+ "f82f0c7421333c2cae5d0d0200e7f4726cda60baecad4ba067c7da17c681e2fb20612991f75763791b228c258f79ec2ecc40788fdda71b8f11a9032417ec7e08")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
CreatePollTransaction transaction = new CreatePollTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIssueAssetTransactionSignature() throws TransformationException {
|
||||
// 3JeJ8yGnG8RCQH51S2qYJT5nfbokjHnBmM7KZsj61HPRy8K3ZWkGHh99QQ6HbRHxnknnjjAsffHRaeca1ap3tcFv
|
||||
byte[] rawTx = HashCode
|
||||
.fromString(
|
||||
"0000000b000001489376bea34d4cbdb644be00b5848a2beeee087fdb98de49a010e686de9540f7d83720cdd182ca6efd1a6225f72f2821ed8a19f236002aef33afa4e2e419fe641c2bc4800a8dd3440f3ce0526c924f2cc15f3fdc1afcf4d57e4502c7a13bfed9851e81abc93a6a24ae1a453205b39d0c3bd24fb5eb675cd199e7cb5b316c00000003787878000000117878787878787878787878787878787878000000000000006400733fa8fa762c404ca1ddd799e93cc8ea292cd9fdd84d5c8b094050d4f576ea56071055f9fe337bf610624514f673e66462f8719759242b5635f19da088b311050000000005f5e100733fa8fa762c404ca1ddd799e93cc8ea292cd9fdd84d5c8b094050d4f576ea56071055f9fe337bf610624514f673e66462f8719759242b5635f19da088b31105")
|
||||
.asBytes();
|
||||
|
||||
TransactionData transactionData = TransactionTransformer.fromBytes(rawTx);
|
||||
|
||||
IssueAssetTransaction transaction = new IssueAssetTransaction(null, transactionData);
|
||||
assertTrue(transaction.isSignatureValid());
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package org.qortal.test.assets;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.test.common.Common;
|
||||
|
||||
public class MixedPricingTests extends Common{
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useSettings("test-settings-old-asset.json");
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws DataException {
|
||||
Common.orphanCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check order matching between 'old' pricing order and 'new' pricing order.
|
||||
* <p>
|
||||
* In this test, the order created under 'old' pricing scheme has
|
||||
* "amount" in have-asset?
|
||||
*/
|
||||
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
package org.qortal.test.assets;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.test.common.AccountUtils;
|
||||
import org.qortal.test.common.AssetUtils;
|
||||
import org.qortal.test.common.Common;
|
||||
import org.qortal.utils.NTP;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
public class OldTradingTests extends Common {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
||||
Common.useSettings("test-settings-old-asset.json");
|
||||
NTP.setFixedOffset(Settings.getInstance().getTestNtpOffset());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws DataException {
|
||||
Common.orphanCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check matching of indivisible amounts.
|
||||
* <p>
|
||||
* We use orders similar to some found in legacy qora1 blockchain
|
||||
* to test for expected results with indivisible assets.
|
||||
* <p>
|
||||
* In addition, although the 3rd "further" order would match up to 999 RUB.iPLZ,
|
||||
* granularity at that price reduces matched amount to 493 RUB.iPLZ.
|
||||
*/
|
||||
@Test
|
||||
public void testOldIndivisible() throws DataException {
|
||||
// Issue some indivisible assets
|
||||
long asset112Id;
|
||||
long asset113Id;
|
||||
try (Repository repository = RepositoryManager.getRepository()) {
|
||||
// Issue indivisible asset
|
||||
asset112Id = AssetUtils.issueAsset(repository, "alice", "RUB.iPLZ", 999999999999L, false);
|
||||
|
||||
// Issue another indivisible asset
|
||||
asset113Id = AssetUtils.issueAsset(repository, "bob", "RU.GZP.V123", 10000L, false);
|
||||
}
|
||||
|
||||
// Transfer some assets so orders can be created
|
||||
try (Repository repository = RepositoryManager.getRepository()) {
|
||||
AssetUtils.transferAsset(repository, "alice", "bob", asset112Id, BigDecimal.valueOf(5000L).setScale(8));
|
||||
AssetUtils.transferAsset(repository, "bob", "alice", asset113Id, BigDecimal.valueOf(5000L).setScale(8));
|
||||
}
|
||||
|
||||
final BigDecimal asset113Amount = new BigDecimal("1000").setScale(8);
|
||||
final BigDecimal asset112Price = new BigDecimal("1.00000000").setScale(8);
|
||||
|
||||
final BigDecimal asset112Amount = new BigDecimal("2000").setScale(8);
|
||||
final BigDecimal asset113Price = new BigDecimal("0.98600000").setScale(8);
|
||||
|
||||
final BigDecimal asset112Matched = new BigDecimal("1000").setScale(8);
|
||||
final BigDecimal asset113Matched = new BigDecimal("1000").setScale(8);
|
||||
|
||||
AssetUtils.genericTradeTest(asset113Id, asset112Id, asset113Amount, asset112Price, asset112Amount, asset113Price, asset113Amount, asset112Amount, asset112Matched, asset113Matched, BigDecimal.ZERO);
|
||||
|
||||
// Further trade
|
||||
final BigDecimal asset113Amount2 = new BigDecimal("986").setScale(8);
|
||||
final BigDecimal asset112Price2 = new BigDecimal("1.00000000").setScale(8);
|
||||
|
||||
final BigDecimal asset112Matched2 = new BigDecimal("500").setScale(8);
|
||||
final BigDecimal asset113Matched2 = new BigDecimal("493").setScale(8);
|
||||
|
||||
try (Repository repository = RepositoryManager.getRepository()) {
|
||||
Map<String, Map<Long, BigDecimal>> initialBalances = AccountUtils.getBalances(repository, asset112Id, asset113Id);
|
||||
|
||||
// Create further order
|
||||
byte[] furtherOrderId = AssetUtils.createOrder(repository, "alice", asset113Id, asset112Id, asset113Amount2, asset112Price2);
|
||||
|
||||
// Check balances to check expected outcome
|
||||
BigDecimal expectedBalance;
|
||||
|
||||
// Alice asset 113
|
||||
expectedBalance = initialBalances.get("alice").get(asset113Id).subtract(asset113Amount2);
|
||||
AccountUtils.assertBalance(repository, "alice", asset113Id, expectedBalance);
|
||||
|
||||
// Alice asset 112
|
||||
expectedBalance = initialBalances.get("alice").get(asset112Id).add(asset112Matched2);
|
||||
AccountUtils.assertBalance(repository, "alice", asset112Id, expectedBalance);
|
||||
|
||||
BigDecimal expectedFulfilled = asset113Matched2;
|
||||
BigDecimal actualFulfilled = repository.getAssetRepository().fromOrderId(furtherOrderId).getFulfilled();
|
||||
assertEqualBigDecimals("Order fulfilled incorrect", expectedFulfilled, actualFulfilled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check legacy partial matching of orders with prices that
|
||||
* can't be represented in floating binary.
|
||||
* <p>
|
||||
* For example, sell 2 GOLD for 24 OTHER so
|
||||
* unit price is 2 / 24 or 0.08333333.
|
||||
* <p>
|
||||
* This inexactness causes the match amount to be
|
||||
* only 1.99999992 instead of the expected 2.00000000.
|
||||
* <p>
|
||||
* However this behaviour is "grandfathered" in legacy/"old"
|
||||
* mode so we need to test.
|
||||
*/
|
||||
@Test
|
||||
public void testOldNonExactFraction() throws DataException {
|
||||
final BigDecimal aliceAmount = new BigDecimal("24.00000000").setScale(8);
|
||||
final BigDecimal alicePrice = new BigDecimal("0.08333333").setScale(8);
|
||||
|
||||
final BigDecimal bobAmount = new BigDecimal("2.00000000").setScale(8);
|
||||
final BigDecimal bobPrice = new BigDecimal("12.00000000").setScale(8);
|
||||
|
||||
final BigDecimal aliceCommitment = aliceAmount;
|
||||
final BigDecimal bobCommitment = bobAmount;
|
||||
|
||||
// Due to rounding these are the expected traded amounts.
|
||||
final BigDecimal aliceReturn = new BigDecimal("1.99999992").setScale(8);
|
||||
final BigDecimal bobReturn = new BigDecimal("24.00000000").setScale(8);
|
||||
|
||||
AssetUtils.genericTradeTest(AssetUtils.goldAssetId, AssetUtils.otherAssetId, aliceAmount, alicePrice, bobAmount, bobPrice, aliceCommitment, bobCommitment, aliceReturn, bobReturn, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check legacy qora1 blockchain matching behaviour.
|
||||
*/
|
||||
@Test
|
||||
public void testQora1Compat() throws DataException {
|
||||
// Asset 61 [ATFunding] was issued by QYsLsfwMRBPnunmuWmFkM4hvGsfooY8ssU with 250,000,000 quantity and was divisible.
|
||||
|
||||
// Target order 2jMinWSBjxaLnQvhcEoWGs2JSdX7qbwxMTZenQXXhjGYDHCJDL6EjXPz5VXYuUfZM5LvRNNbcaeBbM6Xhb4tN53g
|
||||
// Creator was QZyuTa3ygjThaPRhrCp1BW4R5Sed6uAGN8 at 2014-10-23 11:14:42.525000+0:00
|
||||
// Have: 150000 [ATFunding], Price: 1.7000000 QORA
|
||||
|
||||
// Initiating order 3Ufqi52nDL3Gi7KqVXpgebVN5FmLrdq2XyUJ11BwSV4byxQ2z96Q5CQeawGyanhpXS4XkYAaJTrNxsDDDxyxwbMN
|
||||
// Creator was QMRoD3RS5vJ4DVNBhBgGtQG4KT3PhkNALH at 2015-03-27 12:24:02.945000+0:00
|
||||
// Have: 2 QORA, Price: 0.58 [ATFunding]
|
||||
|
||||
// Trade: 1.17647050 [ATFunding] for 1.99999985 QORA
|
||||
|
||||
// We'll use GOLD test asset instead of ATFunding, and OTHER test asset instead of QORA
|
||||
|
||||
final BigDecimal aliceAmount = new BigDecimal("150000").setScale(8);
|
||||
final BigDecimal alicePrice = new BigDecimal("1.70000000").setScale(8);
|
||||
|
||||
final BigDecimal bobAmount = new BigDecimal("2.00000000").setScale(8);
|
||||
final BigDecimal bobPrice = new BigDecimal("0.58000000").setScale(8);
|
||||
|
||||
final BigDecimal aliceCommitment = aliceAmount;
|
||||
final BigDecimal bobCommitment = bobAmount;
|
||||
|
||||
final BigDecimal aliceReturn = new BigDecimal("1.99999985").setScale(8);
|
||||
final BigDecimal bobReturn = new BigDecimal("1.17647050").setScale(8);
|
||||
|
||||
AssetUtils.genericTradeTest(AssetUtils.goldAssetId, AssetUtils.otherAssetId, aliceAmount, alicePrice, bobAmount, bobPrice, aliceCommitment, bobCommitment, aliceReturn, bobReturn, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check legacy qora1 blockchain matching behaviour.
|
||||
*/
|
||||
@Test
|
||||
public void testQora1Compat2() throws DataException {
|
||||
// Asset 95 [Bitcoin] was issued by QiGx93L9rNHSNWCY1bJnQTPwB3nhxYTCUj with 21000000 quantity and was divisible.
|
||||
// Asset 96 [BitBTC] was issued by QiGx93L9rNHSNWCY1bJnQTPwB3nhxYTCUj with 21000000 quantity and was divisible.
|
||||
|
||||
// Target order 3jinKPHEak9xrjeYtCaE1PawwRZeRkhYA6q4A7sqej7f3jio8WwXwXpfLWVZkPQ3h6cVdwPhcDFNgbbrBXcipHee
|
||||
// Creator was QiGx93L9rNHSNWCY1bJnQTPwB3nhxYTCUj at 2015-06-10 20:31:44.840000+0:00
|
||||
// Have: 1000000 [BitBTC], Price: 0.90000000 [Bitcoin]
|
||||
|
||||
// Initiating order Jw1UfgspZ344waF8qLhGJanJXVa32FBoVvMW5ByFkyHvZEumF4fPqbaGMa76ba1imC4WX5t3Roa7r23Ys6rhKAA
|
||||
// Creator was QiGx93L9rNHSNWCY1bJnQTPwB3nhxYTCUj at 2015-06-14 17:49:41.410000+0:00
|
||||
// Have: 73251 [Bitcoin], Price: 1.01 [BitBTC]
|
||||
|
||||
// Trade: 81389.99991860 [BitBTC] for 73250.99992674 [Bitcoin]
|
||||
|
||||
// We'll use TEST test asset instead of BitBTC, and OTHER test asset instead of Bitcoin
|
||||
|
||||
final BigDecimal aliceAmount = new BigDecimal("1000000").setScale(8);
|
||||
final BigDecimal alicePrice = new BigDecimal("0.90000000").setScale(8);
|
||||
|
||||
final BigDecimal bobAmount = new BigDecimal("73251").setScale(8);
|
||||
final BigDecimal bobPrice = new BigDecimal("1.01000000").setScale(8);
|
||||
|
||||
final BigDecimal aliceCommitment = aliceAmount;
|
||||
final BigDecimal bobCommitment = bobAmount;
|
||||
|
||||
final BigDecimal aliceReturn = new BigDecimal("73250.99992674").setScale(8);
|
||||
final BigDecimal bobReturn = new BigDecimal("81389.99991860").setScale(8);
|
||||
|
||||
AssetUtils.genericTradeTest(AssetUtils.testAssetId, AssetUtils.otherAssetId, aliceAmount, alicePrice, bobAmount, bobPrice, aliceCommitment, bobCommitment, aliceReturn, bobReturn, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
}
|
@ -15,7 +15,7 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Map;
|
||||
|
||||
public class NewTradingTests extends Common {
|
||||
public class TradingTests extends Common {
|
||||
|
||||
@Before
|
||||
public void beforeTest() throws DataException {
|
@ -7,7 +7,6 @@ import java.util.Base64;
|
||||
import java.util.Base64.Encoder;
|
||||
|
||||
import org.qortal.account.PrivateKeyAccount;
|
||||
import org.qortal.block.BlockChain;
|
||||
import org.qortal.data.asset.OrderData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.CancelAssetOrderTransactionData;
|
||||
@ -113,8 +112,6 @@ public class AssetUtils {
|
||||
OrderData targetOrderData = repository.getAssetRepository().fromOrderId(targetOrderId);
|
||||
OrderData initiatingOrderData = repository.getAssetRepository().fromOrderId(initiatingOrderId);
|
||||
|
||||
boolean isNewPricing = initiatingOrderData.getTimestamp() > BlockChain.getInstance().getNewAssetPricingTimestamp();
|
||||
|
||||
// Alice selling have asset
|
||||
expectedBalance = initialBalances.get("alice").get(haveAssetId).subtract(aliceCommitment);
|
||||
AccountUtils.assertBalance(repository, "alice", haveAssetId, expectedBalance);
|
||||
@ -132,17 +129,14 @@ public class AssetUtils {
|
||||
AccountUtils.assertBalance(repository, "bob", haveAssetId, expectedBalance);
|
||||
|
||||
// Check orders
|
||||
BigDecimal expectedFulfilled;
|
||||
BigDecimal newPricingAmount = (initiatingOrderData.getHaveAssetId() < initiatingOrderData.getWantAssetId()) ? bobReturn : aliceReturn;
|
||||
BigDecimal expectedFulfilled = (initiatingOrderData.getHaveAssetId() < initiatingOrderData.getWantAssetId()) ? bobReturn : aliceReturn;
|
||||
|
||||
// Check matching order
|
||||
assertNotNull("matching order missing", initiatingOrderData);
|
||||
expectedFulfilled = isNewPricing ? newPricingAmount : aliceReturn;
|
||||
Common.assertEqualBigDecimals(String.format("Bob's order \"fulfilled\" incorrect"), expectedFulfilled, initiatingOrderData.getFulfilled());
|
||||
|
||||
// Check initial order
|
||||
assertNotNull("initial order missing", targetOrderData);
|
||||
expectedFulfilled = isNewPricing ? newPricingAmount : bobReturn;
|
||||
Common.assertEqualBigDecimals(String.format("Alice's order \"fulfilled\" incorrect"), expectedFulfilled, targetOrderData.getFulfilled());
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
"isTestChain": true,
|
||||
"blockTimestampMargin": 500,
|
||||
"transactionExpiryPeriod": 86400000,
|
||||
"maxBlockSize": 2097152,
|
||||
"maxBytesPerUnitFee": 1024,
|
||||
"unitFee": "0.1",
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
{ "height": 1, "reward": 100 },
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
{ "levels": [ 1, 2 ], "share": 0.05 },
|
||||
{ "levels": [ 3, 4 ], "share": 0.10 },
|
||||
{ "levels": [ 5, 6 ], "share": 0.15 },
|
||||
{ "levels": [ 7, 8 ], "share": 0.20 },
|
||||
{ "levels": [ 9, 10 ], "share": 0.25 }
|
||||
],
|
||||
"qoraHoldersShare": 0.20,
|
||||
"qoraPerQortReward": 250,
|
||||
"blocksNeededByLevel": [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ],
|
||||
"blockTimingsByHeight": [
|
||||
{ "height": 1, "target": 60000, "deviation": 30000, "power": 0.2 }
|
||||
],
|
||||
"featureTriggers": {
|
||||
"messageHeight": 0,
|
||||
"atHeight": 0,
|
||||
"assetsTimestamp": 0,
|
||||
"votingTimestamp": 0,
|
||||
"arbitraryTimestamp": 0,
|
||||
"powfixTimestamp": 0,
|
||||
"v2Timestamp": 0,
|
||||
"newAssetPricingTimestamp": 1600000000000,
|
||||
"groupApprovalTimestamp": 0
|
||||
},
|
||||
"genesisInfo": {
|
||||
"version": 4,
|
||||
"timestamp": 0,
|
||||
"transactions": [
|
||||
{ "type": "ISSUE_ASSET", "owner": "QUwGVHPPxJNJ2dq95abQNe79EyBN2K26zM", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0, "reference": "3Verk6ZKBJc3WTTVfxFC9icSjKdM8b92eeJEpJP8qNizG4ZszNFq8wdDYdSjJXq2iogDFR1njyhsBdVpbvDfjzU7" },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QUwGVHPPxJNJ2dq95abQNe79EyBN2K26zM", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QUwGVHPPxJNJ2dq95abQNe79EyBN2K26zM", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||
|
||||
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000", "fee": 0 },
|
||||
|
||||
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "TEST", "description": "test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
||||
{ "type": "ISSUE_ASSET", "owner": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": 1000000, "isDivisible": true, "fee": 0 },
|
||||
|
||||
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
|
||||
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": 100 }
|
||||
]
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
{
|
||||
"isTestChain": true,
|
||||
"blockTimestampMargin": 500,
|
||||
"transactionExpiryPeriod": 86400000,
|
||||
"maxBlockSize": 2097152,
|
||||
"maxBytesPerUnitFee": 1024,
|
||||
"unitFee": "0.1",
|
||||
"requireGroupForApproval": false,
|
||||
"minAccountLevelToRewardShare": 5,
|
||||
"maxRewardSharesPerMintingAccount": 20,
|
||||
"founderEffectiveMintingLevel": 10,
|
||||
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||
"rewardsByHeight": [
|
||||
{ "height": 1, "reward": 100 },
|
||||
{ "height": 11, "reward": 10 },
|
||||
{ "height": 21, "reward": 1 }
|
||||
],
|
||||
"sharesByLevel": [
|
||||
{ "levels": [ 1, 2 ], "share": 0.05 },
|
||||
{ "levels": [ 3, 4 ], "share": 0.10 },
|
||||
{ "levels": [ 5, 6 ], "share": 0.15 },
|
||||
{ "levels": [ 7, 8 ], "share": 0.20 },
|
||||
{ "levels": [ 9, 10 ], "share": 0.25 }
|
||||
],
|
||||
"qoraHoldersShare": 0.20,
|
||||
"qoraPerQortReward": 250,
|
||||
"blocksNeededByLevel": [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ],
|
||||
"blockTimingsByHeight": [
|
||||
{ "height": 1, "target": 60000, "deviation": 30000, "power": 0.2 }
|
||||
],
|
||||
"featureTriggers": {
|
||||
"messageHeight": 0,
|
||||
"atHeight": 0,
|
||||
"assetsTimestamp": 0,
|
||||
"votingTimestamp": 0,
|
||||
"arbitraryTimestamp": 0,
|
||||
"powfixTimestamp": 0,
|
||||
"qortalTimestamp": 1600000000000,
|
||||
"newAssetPricingTimestamp": 1600000000000,
|
||||
"groupApprovalTimestamp": 0
|
||||
},
|
||||
"genesisInfo": {
|
||||
"version": 1,
|
||||
"timestamp": 1400247274336,
|
||||
"transactions": [
|
||||
{ "type": "ISSUE_ASSET", "owner": "QcFmNxSArv5tWEzCtTKb2Lqc5QkKuQ7RNs", "assetName": "QORA", "description": "QORA native coin", "data": "", "quantity": 10000000000, "isDivisible": true, "fee": 0, "reference": "3Verk6ZKBJc3WTTVfxFC9icSjKdM8b92eeJEpJP8qNizG4ZszNFq8wdDYdSjJXq2iogDFR1njyhsBdVpbvDfjzU7" },
|
||||
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000", "fee": 0 },
|
||||
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000", "fee": 0 }
|
||||
]
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"restrictedApi": false,
|
||||
"blockchainConfig": "src/test/resources/test-chain-old-asset.json",
|
||||
"wipeUnconfirmedOnStart": false,
|
||||
"minPeers": 0
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"restrictedApi": false,
|
||||
"blockchainConfig": "src/test/resources/test-chain-v1.json",
|
||||
"wipeUnconfirmedOnStart": false,
|
||||
"minPeers": 0
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user