forked from Qortal/qortal
Fixed warnings, and other improvements.
This commit is contained in:
parent
b571931127
commit
b693a514fd
@ -1173,7 +1173,11 @@ public class ArbitraryResource {
|
|||||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, error);
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Long minLatestBlockTimestamp = NTP.getTime() - (60 * 60 * 1000L);
|
final Long now = NTP.getTime();
|
||||||
|
if (now == null) {
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.NO_TIME_SYNC);
|
||||||
|
}
|
||||||
|
final Long minLatestBlockTimestamp = now - (60 * 60 * 1000L);
|
||||||
if (!Controller.getInstance().isUpToDate(minLatestBlockTimestamp)) {
|
if (!Controller.getInstance().isUpToDate(minLatestBlockTimestamp)) {
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCKCHAIN_NEEDS_SYNC);
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BLOCKCHAIN_NEEDS_SYNC);
|
||||||
}
|
}
|
||||||
@ -1231,7 +1235,7 @@ public class ArbitraryResource {
|
|||||||
// The actual data will be in a randomly-named subfolder of tempDirectory
|
// The actual data will be in a randomly-named subfolder of tempDirectory
|
||||||
// Remove hidden folders, i.e. starting with "_", as some systems can add them, e.g. "__MACOSX"
|
// Remove hidden folders, i.e. starting with "_", as some systems can add them, e.g. "__MACOSX"
|
||||||
String[] files = tempDirectory.toFile().list((parent, child) -> !child.startsWith("_"));
|
String[] files = tempDirectory.toFile().list((parent, child) -> !child.startsWith("_"));
|
||||||
if (files.length == 1) { // Single directory or file only
|
if (files != null && files.length == 1) { // Single directory or file only
|
||||||
path = Paths.get(tempDirectory.toString(), files[0]).toString();
|
path = Paths.get(tempDirectory.toString(), files[0]).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,6 @@ public class ArbitraryDataBuilder {
|
|||||||
/**
|
/**
|
||||||
* Process transactions, but do not build anything
|
* Process transactions, but do not build anything
|
||||||
* This is useful for checking the status of a given resource
|
* This is useful for checking the status of a given resource
|
||||||
*
|
|
||||||
* @throws DataException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws MissingDataException
|
|
||||||
*/
|
*/
|
||||||
public void process() throws DataException, IOException, MissingDataException {
|
public void process() throws DataException, IOException, MissingDataException {
|
||||||
this.fetchTransactions();
|
this.fetchTransactions();
|
||||||
@ -69,10 +65,6 @@ public class ArbitraryDataBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the latest state of a given resource
|
* Build the latest state of a given resource
|
||||||
*
|
|
||||||
* @throws DataException
|
|
||||||
* @throws IOException
|
|
||||||
* @throws MissingDataException
|
|
||||||
*/
|
*/
|
||||||
public void build() throws DataException, IOException, MissingDataException {
|
public void build() throws DataException, IOException, MissingDataException {
|
||||||
this.process();
|
this.process();
|
||||||
|
@ -9,7 +9,6 @@ import org.qortal.arbitrary.exception.MissingDataException;
|
|||||||
import org.qortal.arbitrary.misc.Service;
|
import org.qortal.arbitrary.misc.Service;
|
||||||
import org.qortal.controller.arbitrary.ArbitraryDataBuildManager;
|
import org.qortal.controller.arbitrary.ArbitraryDataBuildManager;
|
||||||
import org.qortal.controller.arbitrary.ArbitraryDataManager;
|
import org.qortal.controller.arbitrary.ArbitraryDataManager;
|
||||||
import org.qortal.controller.arbitrary.ArbitraryDataStorageManager;
|
|
||||||
import org.qortal.crypto.AES;
|
import org.qortal.crypto.AES;
|
||||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||||
import org.qortal.data.transaction.ArbitraryTransactionData.*;
|
import org.qortal.data.transaction.ArbitraryTransactionData.*;
|
||||||
@ -154,9 +153,6 @@ public class ArbitraryDataReader {
|
|||||||
* If no exception is thrown, you can then use getFilePath() to access the data immediately after returning
|
* If no exception is thrown, you can then use getFilePath() to access the data immediately after returning
|
||||||
*
|
*
|
||||||
* @param overwrite - set to true to force rebuild an existing cache
|
* @param overwrite - set to true to force rebuild an existing cache
|
||||||
* @throws IOException
|
|
||||||
* @throws DataException
|
|
||||||
* @throws MissingDataException
|
|
||||||
*/
|
*/
|
||||||
public void loadSynchronously(boolean overwrite) throws DataException, IOException, MissingDataException {
|
public void loadSynchronously(boolean overwrite) throws DataException, IOException, MissingDataException {
|
||||||
try {
|
try {
|
||||||
@ -223,7 +219,6 @@ public class ArbitraryDataReader {
|
|||||||
/**
|
/**
|
||||||
* Working directory should only be deleted on failure, since it is currently used to
|
* Working directory should only be deleted on failure, since it is currently used to
|
||||||
* serve a cached version of the resource for subsequent requests.
|
* serve a cached version of the resource for subsequent requests.
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
private void deleteWorkingDirectory() {
|
private void deleteWorkingDirectory() {
|
||||||
try {
|
try {
|
||||||
@ -303,7 +298,7 @@ public class ArbitraryDataReader {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new DataException(String.format("Unknown resource ID type specified: %s", resourceIdType.toString()));
|
throw new DataException(String.format("Unknown resource ID type specified: %s", resourceIdType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,6 +363,9 @@ public class ArbitraryDataReader {
|
|||||||
// Load data file(s)
|
// Load data file(s)
|
||||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromTransactionData(transactionData);
|
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromTransactionData(transactionData);
|
||||||
ArbitraryTransactionUtils.checkAndRelocateMiscFiles(transactionData);
|
ArbitraryTransactionUtils.checkAndRelocateMiscFiles(transactionData);
|
||||||
|
if (arbitraryDataFile == null) {
|
||||||
|
throw new DataException(String.format("arbitraryDataFile is null"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!arbitraryDataFile.allFilesExist()) {
|
if (!arbitraryDataFile.allFilesExist()) {
|
||||||
if (ListUtils.isNameBlocked(transactionData.getName())) {
|
if (ListUtils.isNameBlocked(transactionData.getName())) {
|
||||||
|
@ -150,6 +150,9 @@ public class ArbitraryDataResource {
|
|||||||
|
|
||||||
for (ArbitraryTransactionData transactionData : transactionDataList) {
|
for (ArbitraryTransactionData transactionData : transactionDataList) {
|
||||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromTransactionData(transactionData);
|
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromTransactionData(transactionData);
|
||||||
|
if (arbitraryDataFile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete any chunks or complete files from each transaction
|
// Delete any chunks or complete files from each transaction
|
||||||
arbitraryDataFile.deleteAll(deleteMetadata);
|
arbitraryDataFile.deleteAll(deleteMetadata);
|
||||||
|
@ -504,110 +504,118 @@ public class OnlineAccountsManager {
|
|||||||
computeOurAccountsForTimestamp(onlineAccountsTimestamp);
|
computeOurAccountsForTimestamp(onlineAccountsTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean computeOurAccountsForTimestamp(long onlineAccountsTimestamp) {
|
private boolean computeOurAccountsForTimestamp(Long onlineAccountsTimestamp) {
|
||||||
List<MintingAccountData> mintingAccounts;
|
if (onlineAccountsTimestamp != null) {
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
List<MintingAccountData> mintingAccounts;
|
||||||
mintingAccounts = repository.getAccountRepository().getMintingAccounts();
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
mintingAccounts = repository.getAccountRepository().getMintingAccounts();
|
||||||
|
|
||||||
// We have no accounts to send
|
// We have no accounts to send
|
||||||
if (mintingAccounts.isEmpty())
|
if (mintingAccounts.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only active reward-shares allowed
|
||||||
|
Iterator<MintingAccountData> iterator = mintingAccounts.iterator();
|
||||||
|
int i = 0;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
MintingAccountData mintingAccountData = iterator.next();
|
||||||
|
|
||||||
|
RewardShareData rewardShareData = repository.getAccountRepository().getRewardShare(mintingAccountData.getPublicKey());
|
||||||
|
if (rewardShareData == null) {
|
||||||
|
// Reward-share doesn't even exist - probably not a good sign
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Account mintingAccount = new Account(repository, rewardShareData.getMinter());
|
||||||
|
if (!mintingAccount.canMint()) {
|
||||||
|
// Minting-account component of reward-share can no longer mint - disregard
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++i > 1 + 1) {
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DataException e) {
|
||||||
|
LOGGER.warn(String.format("Repository issue trying to fetch minting accounts: %s", e.getMessage()));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Only active reward-shares allowed
|
byte[] timestampBytes = Longs.toByteArray(onlineAccountsTimestamp);
|
||||||
Iterator<MintingAccountData> iterator = mintingAccounts.iterator();
|
List<OnlineAccountData> ourOnlineAccounts = new ArrayList<>();
|
||||||
while (iterator.hasNext()) {
|
|
||||||
MintingAccountData mintingAccountData = iterator.next();
|
|
||||||
|
|
||||||
RewardShareData rewardShareData = repository.getAccountRepository().getRewardShare(mintingAccountData.getPublicKey());
|
int remaining = mintingAccounts.size();
|
||||||
if (rewardShareData == null) {
|
for (MintingAccountData mintingAccountData : mintingAccounts) {
|
||||||
// Reward-share doesn't even exist - probably not a good sign
|
remaining--;
|
||||||
iterator.remove();
|
byte[] privateKey = mintingAccountData.getPrivateKey();
|
||||||
|
byte[] publicKey = Crypto.toPublicKey(privateKey);
|
||||||
|
|
||||||
|
// We don't want to compute the online account nonce and signature again if it already exists
|
||||||
|
Set<OnlineAccountData> onlineAccounts = this.currentOnlineAccounts.computeIfAbsent(onlineAccountsTimestamp, k -> ConcurrentHashMap.newKeySet());
|
||||||
|
boolean alreadyExists = onlineAccounts.stream().anyMatch(a -> Arrays.equals(a.getPublicKey(), publicKey));
|
||||||
|
if (alreadyExists) {
|
||||||
|
this.hasOurOnlineAccounts = true;
|
||||||
|
|
||||||
|
if (remaining > 0) {
|
||||||
|
// Move on to next account
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// Everything exists, so return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate bytes for mempow
|
||||||
|
byte[] mempowBytes;
|
||||||
|
try {
|
||||||
|
mempowBytes = this.getMemoryPoWBytes(publicKey, onlineAccountsTimestamp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOGGER.info("Unable to create bytes for MemoryPoW. Moving on to next account...");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Account mintingAccount = new Account(repository, rewardShareData.getMinter());
|
// Compute nonce
|
||||||
if (!mintingAccount.canMint()) {
|
Integer nonce;
|
||||||
// Minting-account component of reward-share can no longer mint - disregard
|
try {
|
||||||
iterator.remove();
|
nonce = this.computeMemoryPoW(mempowBytes, publicKey, onlineAccountsTimestamp);
|
||||||
continue;
|
if (nonce == null) {
|
||||||
}
|
// A nonce is required
|
||||||
}
|
return false;
|
||||||
} catch (DataException e) {
|
}
|
||||||
LOGGER.warn(String.format("Repository issue trying to fetch minting accounts: %s", e.getMessage()));
|
} catch (TimeoutException e) {
|
||||||
return false;
|
LOGGER.info(String.format("Timed out computing nonce for account %.8s", Base58.encode(publicKey)));
|
||||||
}
|
|
||||||
|
|
||||||
byte[] timestampBytes = Longs.toByteArray(onlineAccountsTimestamp);
|
|
||||||
List<OnlineAccountData> ourOnlineAccounts = new ArrayList<>();
|
|
||||||
|
|
||||||
int remaining = mintingAccounts.size();
|
|
||||||
for (MintingAccountData mintingAccountData : mintingAccounts) {
|
|
||||||
remaining--;
|
|
||||||
byte[] privateKey = mintingAccountData.getPrivateKey();
|
|
||||||
byte[] publicKey = Crypto.toPublicKey(privateKey);
|
|
||||||
|
|
||||||
// We don't want to compute the online account nonce and signature again if it already exists
|
|
||||||
Set<OnlineAccountData> onlineAccounts = this.currentOnlineAccounts.computeIfAbsent(onlineAccountsTimestamp, k -> ConcurrentHashMap.newKeySet());
|
|
||||||
boolean alreadyExists = onlineAccounts.stream().anyMatch(a -> Arrays.equals(a.getPublicKey(), publicKey));
|
|
||||||
if (alreadyExists) {
|
|
||||||
this.hasOurOnlineAccounts = true;
|
|
||||||
|
|
||||||
if (remaining > 0) {
|
|
||||||
// Move on to next account
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Everything exists, so return true
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate bytes for mempow
|
|
||||||
byte[] mempowBytes;
|
|
||||||
try {
|
|
||||||
mempowBytes = this.getMemoryPoWBytes(publicKey, onlineAccountsTimestamp);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
LOGGER.info("Unable to create bytes for MemoryPoW. Moving on to next account...");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute nonce
|
|
||||||
Integer nonce;
|
|
||||||
try {
|
|
||||||
nonce = this.computeMemoryPoW(mempowBytes, publicKey, onlineAccountsTimestamp);
|
|
||||||
if (nonce == null) {
|
|
||||||
// A nonce is required
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (TimeoutException e) {
|
|
||||||
LOGGER.info(String.format("Timed out computing nonce for account %.8s", Base58.encode(publicKey)));
|
byte[] signature = Qortal25519Extras.signForAggregation(privateKey, timestampBytes);
|
||||||
|
|
||||||
|
// Our account is online
|
||||||
|
OnlineAccountData ourOnlineAccountData = new OnlineAccountData(onlineAccountsTimestamp, signature, publicKey, nonce);
|
||||||
|
|
||||||
|
// Make sure to verify before adding
|
||||||
|
if (verifyMemoryPoW(ourOnlineAccountData, null)) {
|
||||||
|
ourOnlineAccounts.add(ourOnlineAccountData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasOurOnlineAccounts = !ourOnlineAccounts.isEmpty();
|
||||||
|
|
||||||
|
boolean hasInfoChanged = addAccounts(ourOnlineAccounts);
|
||||||
|
|
||||||
|
if (!hasInfoChanged)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
byte[] signature = Qortal25519Extras.signForAggregation(privateKey, timestampBytes);
|
Network.getInstance().broadcast(peer -> new OnlineAccountsV3Message(ourOnlineAccounts));
|
||||||
|
|
||||||
// Our account is online
|
LOGGER.debug("Broadcasted {} online account{} with timestamp {}", ourOnlineAccounts.size(), (ourOnlineAccounts.size() != 1 ? "s" : ""), onlineAccountsTimestamp);
|
||||||
OnlineAccountData ourOnlineAccountData = new OnlineAccountData(onlineAccountsTimestamp, signature, publicKey, nonce);
|
|
||||||
|
|
||||||
// Make sure to verify before adding
|
return true;
|
||||||
if (verifyMemoryPoW(ourOnlineAccountData, null)) {
|
|
||||||
ourOnlineAccounts.add(ourOnlineAccountData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hasOurOnlineAccounts = !ourOnlineAccounts.isEmpty();
|
return false;
|
||||||
|
|
||||||
boolean hasInfoChanged = addAccounts(ourOnlineAccounts);
|
|
||||||
|
|
||||||
if (!hasInfoChanged)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Network.getInstance().broadcast(peer -> new OnlineAccountsV3Message(ourOnlineAccounts));
|
|
||||||
|
|
||||||
LOGGER.debug("Broadcasted {} online account{} with timestamp {}", ourOnlineAccounts.size(), (ourOnlineAccounts.size() != 1 ? "s" : ""), onlineAccountsTimestamp);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user