forked from Qortal/qortal
Use a random last reference on the very first transaction for an account
This is needed because we want to allow brand new accounts to publish data without a fee. A similar approach to CrossChainResource.buildAtMessage(). We already require PoW on all arbitrary transactions, so no additional logic beyond this should be needed.
This commit is contained in:
parent
1d62ef357d
commit
47ff51ce4e
@ -15,6 +15,7 @@ import java.net.UnknownHostException;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
@ -53,6 +54,7 @@ import org.qortal.transaction.Transaction;
|
|||||||
import org.qortal.transaction.Transaction.TransactionType;
|
import org.qortal.transaction.Transaction.TransactionType;
|
||||||
import org.qortal.transaction.Transaction.ValidationResult;
|
import org.qortal.transaction.Transaction.ValidationResult;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
|
import org.qortal.transform.Transformer;
|
||||||
import org.qortal.transform.transaction.ArbitraryTransactionTransformer;
|
import org.qortal.transform.transaction.ArbitraryTransactionTransformer;
|
||||||
import org.qortal.utils.Base58;
|
import org.qortal.utils.Base58;
|
||||||
import org.qortal.utils.NTP;
|
import org.qortal.utils.NTP;
|
||||||
@ -269,10 +271,14 @@ public class ArbitraryResource {
|
|||||||
}
|
}
|
||||||
byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58);
|
byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58);
|
||||||
final String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
final String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
||||||
final byte[] lastReference = repository.getAccountRepository().getLastReference(creatorAddress);
|
byte[] lastReference = repository.getAccountRepository().getLastReference(creatorAddress);
|
||||||
if (lastReference == null) {
|
if (lastReference == null) {
|
||||||
LOGGER.info(String.format("Qortal account %s has no last reference", creatorAddress));
|
// Use a random last reference on the very first transaction for an account
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
// Code copied from CrossChainResource.buildAtMessage()
|
||||||
|
// We already require PoW on all arbitrary transactions, so no additional logic is needed
|
||||||
|
Random random = new Random();
|
||||||
|
lastReference = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
|
random.nextBytes(lastReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = null;
|
String name = null;
|
||||||
|
@ -15,6 +15,7 @@ import java.nio.file.Paths;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@ -48,6 +49,7 @@ import org.qortal.arbitrary.ArbitraryDataWriter;
|
|||||||
import org.qortal.transaction.ArbitraryTransaction;
|
import org.qortal.transaction.ArbitraryTransaction;
|
||||||
import org.qortal.transaction.Transaction;
|
import org.qortal.transaction.Transaction;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
|
import org.qortal.transform.Transformer;
|
||||||
import org.qortal.transform.transaction.ArbitraryTransactionTransformer;
|
import org.qortal.transform.transaction.ArbitraryTransactionTransformer;
|
||||||
import org.qortal.utils.Base58;
|
import org.qortal.utils.Base58;
|
||||||
import org.qortal.utils.NTP;
|
import org.qortal.utils.NTP;
|
||||||
@ -104,10 +106,14 @@ public class WebsiteResource {
|
|||||||
}
|
}
|
||||||
byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58);
|
byte[] creatorPublicKey = Base58.decode(creatorPublicKeyBase58);
|
||||||
final String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
final String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
||||||
final byte[] lastReference = repository.getAccountRepository().getLastReference(creatorAddress);
|
byte[] lastReference = repository.getAccountRepository().getLastReference(creatorAddress);
|
||||||
if (lastReference == null) {
|
if (lastReference == null) {
|
||||||
LOGGER.info(String.format("Qortal account %s has no last reference", creatorAddress));
|
// Use a random last reference on the very first transaction for an account
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
// Code copied from CrossChainResource.buildAtMessage()
|
||||||
|
// We already require PoW on all arbitrary transactions, so no additional logic is needed
|
||||||
|
Random random = new Random();
|
||||||
|
lastReference = new byte[Transformer.SIGNATURE_LENGTH];
|
||||||
|
random.nextBytes(lastReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = "CalDescentTest1"; // TODO: dynamic
|
String name = "CalDescentTest1"; // TODO: dynamic
|
||||||
|
@ -74,6 +74,26 @@ public class ArbitraryTransaction extends Transaction {
|
|||||||
this.arbitraryTransactionData.setNonce(MemoryPoW.compute2(transactionBytes, POW_BUFFER_SIZE, difficulty));
|
this.arbitraryTransactionData.setNonce(MemoryPoW.compute2(transactionBytes, POW_BUFFER_SIZE, difficulty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasValidReference() throws DataException {
|
||||||
|
// We shouldn't really get this far, but just in case:
|
||||||
|
if (this.arbitraryTransactionData.getReference() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the account current doesn't have a last reference, and the fee is 0, we will allow any value.
|
||||||
|
// This ensures that the first transaction for an account will be valid whilst still validating
|
||||||
|
// the last reference from the second transaction onwards. By checking for a zero fee, we ensure
|
||||||
|
// standard last reference validation when fee > 0.
|
||||||
|
Account creator = getCreator();
|
||||||
|
Long fee = this.arbitraryTransactionData.getFee();
|
||||||
|
if (creator.getLastReference() == null && fee == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.hasValidReference();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult isValid() throws DataException {
|
public ValidationResult isValid() throws DataException {
|
||||||
// Check that some data - or a data hash - has been supplied
|
// Check that some data - or a data hash - has been supplied
|
||||||
|
Loading…
Reference in New Issue
Block a user