diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index 7a2be548..8551e4e7 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -357,7 +357,7 @@ public class Block { System.arraycopy(onlineAccountData.getSignature(), 0, onlineAccountsSignatures, i * Transformer.SIGNATURE_LENGTH, Transformer.SIGNATURE_LENGTH); } - byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData.getMinterSignature(), + byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData, minter.getPublicKey(), encodedOnlineAccounts)); // Qortal: minter is always a reward-share, so find actual minter and get their effective minting level @@ -424,7 +424,7 @@ public class Block { int version = this.blockData.getVersion(); byte[] reference = this.blockData.getReference(); - byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData.getMinterSignature(), + byte[] minterSignature = minter.sign(BlockTransformer.getBytesForMinterSignature(parentBlockData, minter.getPublicKey(), this.blockData.getEncodedOnlineAccounts())); // Qortal: minter is always a reward-share, so find actual minter and get their effective minting level @@ -738,11 +738,7 @@ public class Block { if (!(this.minter instanceof PrivateKeyAccount)) throw new IllegalStateException("Block's minter is not a PrivateKeyAccount - can't sign!"); - try { - this.blockData.setMinterSignature(((PrivateKeyAccount) this.minter).sign(BlockTransformer.getBytesForMinterSignature(this.blockData))); - } catch (TransformationException e) { - throw new RuntimeException("Unable to calculate block's minter signature", e); - } + this.blockData.setMinterSignature(((PrivateKeyAccount) this.minter).sign(BlockTransformer.getBytesForMinterSignature(this.blockData))); } /** diff --git a/src/main/java/org/qortal/block/BlockChain.java b/src/main/java/org/qortal/block/BlockChain.java index ad9140e3..b3221619 100644 --- a/src/main/java/org/qortal/block/BlockChain.java +++ b/src/main/java/org/qortal/block/BlockChain.java @@ -70,7 +70,8 @@ public class BlockChain { private GenesisBlock.GenesisInfo genesisInfo; public enum FeatureTrigger { - atFindNextTransactionFix; + atFindNextTransactionFix, + newBlockSigHeight; } /** Map of which blockchain features are enabled when (height/timestamp) */ @@ -376,6 +377,10 @@ public class BlockChain { return this.featureTriggers.get(FeatureTrigger.atFindNextTransactionFix.name()).intValue(); } + public int getNewBlockSigHeight() { + return this.featureTriggers.get(FeatureTrigger.newBlockSigHeight.name()).intValue(); + } + // More complex getters for aspects that change by height or timestamp public long getRewardAtHeight(int ourHeight) { diff --git a/src/main/java/org/qortal/transform/block/BlockTransformer.java b/src/main/java/org/qortal/transform/block/BlockTransformer.java index fcc0bcad..8b91fd11 100644 --- a/src/main/java/org/qortal/transform/block/BlockTransformer.java +++ b/src/main/java/org/qortal/transform/block/BlockTransformer.java @@ -326,24 +326,36 @@ public class BlockTransformer extends Transformer { } } - public static byte[] getMinterSignatureFromReference(byte[] blockReference) { - return Arrays.copyOf(blockReference, MINTER_SIGNATURE_LENGTH); + private static byte[] getReferenceBytesForMinterSignature(int blockHeight, byte[] reference) { + int newBlockSigTriggerHeight = BlockChain.getInstance().getNewBlockSigHeight(); + + return blockHeight >= newBlockSigTriggerHeight + // 'new' block sig uses all of previous block's signature + ? reference + // 'old' block sig only uses first 64 bytes of previous block's signature + : Arrays.copyOf(reference, MINTER_SIGNATURE_LENGTH); } - public static byte[] getBytesForMinterSignature(BlockData blockData) throws TransformationException { - byte[] minterSignature = getMinterSignatureFromReference(blockData.getReference()); + public static byte[] getBytesForMinterSignature(BlockData blockData) { + byte[] referenceBytes = getReferenceBytesForMinterSignature(blockData.getHeight(), blockData.getReference()); - return getBytesForMinterSignature(minterSignature, blockData.getMinterPublicKey(), blockData.getEncodedOnlineAccounts()); + return getBytesForMinterSignature(referenceBytes, blockData.getMinterPublicKey(), blockData.getEncodedOnlineAccounts()); } - public static byte[] getBytesForMinterSignature(byte[] minterSignature, byte[] minterPublicKey, byte[] encodedOnlineAccounts) { - byte[] bytes = new byte[MINTER_SIGNATURE_LENGTH + MINTER_PUBLIC_KEY_LENGTH + encodedOnlineAccounts.length]; + public static byte[] getBytesForMinterSignature(BlockData parentBlockData, byte[] minterPublicKey, byte[] encodedOnlineAccounts) { + byte[] referenceBytes = getReferenceBytesForMinterSignature(parentBlockData.getHeight() + 1, parentBlockData.getSignature()); - System.arraycopy(minterSignature, 0, bytes, 0, MINTER_SIGNATURE_LENGTH); + return getBytesForMinterSignature(referenceBytes, minterPublicKey, encodedOnlineAccounts); + } - System.arraycopy(minterPublicKey, 0, bytes, MINTER_SIGNATURE_LENGTH, MINTER_PUBLIC_KEY_LENGTH); + private static byte[] getBytesForMinterSignature(byte[] referenceBytes, byte[] minterPublicKey, byte[] encodedOnlineAccounts) { + byte[] bytes = new byte[referenceBytes.length + MINTER_PUBLIC_KEY_LENGTH + encodedOnlineAccounts.length]; - System.arraycopy(encodedOnlineAccounts, 0, bytes, MINTER_SIGNATURE_LENGTH + MINTER_PUBLIC_KEY_LENGTH, encodedOnlineAccounts.length); + System.arraycopy(referenceBytes, 0, bytes, 0, referenceBytes.length); + + System.arraycopy(minterPublicKey, 0, bytes, referenceBytes.length, MINTER_PUBLIC_KEY_LENGTH); + + System.arraycopy(encodedOnlineAccounts, 0, bytes, referenceBytes.length + MINTER_PUBLIC_KEY_LENGTH, encodedOnlineAccounts.length); return bytes; } diff --git a/src/main/resources/blockchain.json b/src/main/resources/blockchain.json index 5b9a6202..22da87ac 100644 --- a/src/main/resources/blockchain.json +++ b/src/main/resources/blockchain.json @@ -48,7 +48,8 @@ "minutesPerBlock": 1 }, "featureTriggers": { - "atFindNextTransactionFix": 275000 + "atFindNextTransactionFix": 275000, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-founder-rewards.json b/src/test/resources/test-chain-v2-founder-rewards.json index 84b74e50..6f3c5fff 100644 --- a/src/test/resources/test-chain-v2-founder-rewards.json +++ b/src/test/resources/test-chain-v2-founder-rewards.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-leftover-reward.json b/src/test/resources/test-chain-v2-leftover-reward.json index 53a8f578..53e13915 100644 --- a/src/test/resources/test-chain-v2-leftover-reward.json +++ b/src/test/resources/test-chain-v2-leftover-reward.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-minting.json b/src/test/resources/test-chain-v2-minting.json index cfbca70a..a5c841a0 100644 --- a/src/test/resources/test-chain-v2-minting.json +++ b/src/test/resources/test-chain-v2-minting.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-qora-holder-extremes.json b/src/test/resources/test-chain-v2-qora-holder-extremes.json index 95caadba..883e36fe 100644 --- a/src/test/resources/test-chain-v2-qora-holder-extremes.json +++ b/src/test/resources/test-chain-v2-qora-holder-extremes.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-qora-holder.json b/src/test/resources/test-chain-v2-qora-holder.json index 8f94c255..a06dda7f 100644 --- a/src/test/resources/test-chain-v2-qora-holder.json +++ b/src/test/resources/test-chain-v2-qora-holder.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2-reward-scaling.json b/src/test/resources/test-chain-v2-reward-scaling.json index 7c258928..91d6a36b 100644 --- a/src/test/resources/test-chain-v2-reward-scaling.json +++ b/src/test/resources/test-chain-v2-reward-scaling.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4, diff --git a/src/test/resources/test-chain-v2.json b/src/test/resources/test-chain-v2.json index 783c3183..dd8377be 100644 --- a/src/test/resources/test-chain-v2.json +++ b/src/test/resources/test-chain-v2.json @@ -45,7 +45,8 @@ "qortalTimestamp": 0, "newAssetPricingTimestamp": 0, "groupApprovalTimestamp": 0, - "atFindNextTransactionFix": 0 + "atFindNextTransactionFix": 0, + "newBlockSigHeight": 999999 }, "genesisInfo": { "version": 4,