diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index 99a82808..5e838458 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -1072,7 +1072,7 @@ public class Block { // Validate the rest for (OnlineAccountData onlineAccount : onlineAccounts) - if (!OnlineAccountsManager.getInstance().verifyMemoryPoW(onlineAccount)) + if (!OnlineAccountsManager.getInstance().verifyMemoryPoW(onlineAccount, null)) return ValidationResult.ONLINE_ACCOUNT_NONCE_INCORRECT; // Cache the valid online accounts as they will likely be needed for the next block diff --git a/src/main/java/org/qortal/controller/OnlineAccountsManager.java b/src/main/java/org/qortal/controller/OnlineAccountsManager.java index 53968cfd..1aea118b 100644 --- a/src/main/java/org/qortal/controller/OnlineAccountsManager.java +++ b/src/main/java/org/qortal/controller/OnlineAccountsManager.java @@ -72,6 +72,11 @@ public class OnlineAccountsManager { public static final int POW_BUFFER_SIZE_TESTNET = 1 * 1024 * 1024; // bytes public static final int POW_DIFFICULTY_TESTNET = 5; // leading zero bits + // IMPORTANT: if we ever need to dynamically modify the buffer size using a feature trigger, the + // pre-allocated buffer below will NOT work, and we should instead use a dynamically allocated + // one for the transition period. + private static long[] POW_VERIFY_WORK_BUFFER = new long[getPoWBufferSize() / 8]; + private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(4, new NamedThreadFactory("OnlineAccounts")); private volatile boolean isStopping = false; @@ -339,7 +344,7 @@ public class OnlineAccountsManager { } // Validate mempow - if (!getInstance().verifyMemoryPoW(onlineAccountData)) { + if (!getInstance().verifyMemoryPoW(onlineAccountData, POW_VERIFY_WORK_BUFFER)) { LOGGER.trace(() -> String.format("Rejecting online reward-share for account %s due to invalid PoW nonce", mintingAccount.getAddress())); return false; } @@ -582,7 +587,7 @@ public class OnlineAccountsManager { OnlineAccountData ourOnlineAccountData = new OnlineAccountData(onlineAccountsTimestamp, signature, publicKey, nonce); // Make sure to verify before adding - if (verifyMemoryPoW(ourOnlineAccountData)) { + if (verifyMemoryPoW(ourOnlineAccountData, null)) { ourOnlineAccounts.add(ourOnlineAccountData); } } @@ -637,7 +642,7 @@ public class OnlineAccountsManager { return nonce; } - public boolean verifyMemoryPoW(OnlineAccountData onlineAccountData) { + public boolean verifyMemoryPoW(OnlineAccountData onlineAccountData, long[] workBuffer) { // Require a valid nonce value if (onlineAccountData.getNonce() == null || onlineAccountData.getNonce() < 0) { return false; @@ -653,7 +658,7 @@ public class OnlineAccountsManager { } // Verify the nonce - return MemoryPoW.verify2(mempowBytes, getPoWBufferSize(), getPoWDifficulty(), nonce); + return MemoryPoW.verify2(mempowBytes, workBuffer, getPoWBufferSize(), getPoWDifficulty(), nonce); } diff --git a/src/main/java/org/qortal/crypto/MemoryPoW.java b/src/main/java/org/qortal/crypto/MemoryPoW.java index f27c8f7a..634b8f9b 100644 --- a/src/main/java/org/qortal/crypto/MemoryPoW.java +++ b/src/main/java/org/qortal/crypto/MemoryPoW.java @@ -99,6 +99,10 @@ public class MemoryPoW { } public static boolean verify2(byte[] data, int workBufferLength, long difficulty, int nonce) { + return verify2(data, null, workBufferLength, difficulty, nonce); + } + + public static boolean verify2(byte[] data, long[] workBuffer, int workBufferLength, long difficulty, int nonce) { // Hash data with SHA256 byte[] hash = Crypto.digest(data); @@ -111,7 +115,10 @@ public class MemoryPoW { byteBuffer = null; int longBufferLength = workBufferLength / 8; - long[] workBuffer = new long[longBufferLength]; + + if (workBuffer == null) + workBuffer = new long[longBufferLength]; + long[] state = new long[4]; long seed = 8682522807148012L;