From 91925cf931d719e141b05a81e46447a18d96c07b Mon Sep 17 00:00:00 2001 From: catbref Date: Sat, 20 Feb 2021 12:08:51 +0000 Subject: [PATCH] Change block "minter" signature code, to take effect at some future (undecided) height. Post trigger, this change will use all 128 bytes of previous block's signature when calculating/validating next block's "minter" signature (itself the first 64 bytes of a block signature). Prior to trigger, current behaviour is to only use first 64 bytes of previous block's signature, which doesn't encompass transactions signature. New block sig code should help reduce forking and help improve transactional security. Added "newBlockSigHeight" to blockchain.json but initially set to block 999999 pending decision on when to merge, auto-update, go-live, etc. --- src/main/java/org/qortal/block/Block.java | 10 ++---- .../java/org/qortal/block/BlockChain.java | 7 +++- .../transform/block/BlockTransformer.java | 32 +++++++++++++------ src/main/resources/blockchain.json | 3 +- .../test-chain-v2-founder-rewards.json | 3 +- .../test-chain-v2-leftover-reward.json | 3 +- src/test/resources/test-chain-v2-minting.json | 3 +- .../test-chain-v2-qora-holder-extremes.json | 3 +- .../resources/test-chain-v2-qora-holder.json | 3 +- .../test-chain-v2-reward-scaling.json | 3 +- src/test/resources/test-chain-v2.json | 3 +- 11 files changed, 47 insertions(+), 26 deletions(-) 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,