Performance improvement when checking block's online accounts signatures.

If the timestamp-pubkey-sig is still 'current' then it'll be in
Controller's list of current online accounts, so we can quickly scan
that list before falling back to the more expensive Ed25519 verify.

Added equals() and hashCode() to OnlineAccountData to support above.
This commit is contained in:
catbref 2020-04-16 12:25:01 +01:00
parent c2a3c1271c
commit 8dbd8c4e65
2 changed files with 57 additions and 15 deletions

View File

@ -916,9 +916,11 @@ public class Block {
expandedAccounts.add(rewardShareData);
}
// Possibly check signatures if block is recent
// If block is past a certain age then we simply assume the signatures were correct
long signatureRequirementThreshold = NTP.getTime() - BlockChain.getInstance().getOnlineAccountSignaturesMinLifetime();
if (this.blockData.getTimestamp() >= signatureRequirementThreshold) {
if (this.blockData.getTimestamp() < signatureRequirementThreshold)
return ValidationResult.OK;
if (this.blockData.getOnlineAccountsSignatures() == null || this.blockData.getOnlineAccountsSignatures().length == 0)
return ValidationResult.ONLINE_ACCOUNT_SIGNATURES_MISSING;
@ -927,16 +929,22 @@ public class Block {
// Check signatures
List<byte[]> onlineAccountsSignatures = BlockTransformer.decodeTimestampSignatures(this.blockData.getOnlineAccountsSignatures());
byte[] message = Longs.toByteArray(this.blockData.getOnlineAccountsTimestamp());
long onlineTimestamp = this.blockData.getOnlineAccountsTimestamp();
byte[] onlineTimestampBytes = Longs.toByteArray(onlineTimestamp);
List<OnlineAccountData> onlineAccounts = Controller.getInstance().getOnlineAccounts();
for (int i = 0; i < onlineAccountsSignatures.size(); ++i) {
PublicKeyAccount account = new PublicKeyAccount(null, expandedAccounts.get(i).getRewardSharePublicKey());
byte[] signature = onlineAccountsSignatures.get(i);
byte[] publicKey = expandedAccounts.get(i).getRewardSharePublicKey();
if (!account.verify(signature, message))
// If signature is still current then no need to perform Ed25519 verify
OnlineAccountData onlineAccountData = new OnlineAccountData(onlineTimestamp, signature, publicKey);
if (onlineAccounts.remove(onlineAccountData)) // remove() is like contains() but also reduces the number to check next time
continue;
if (!PublicKeyAccount.verify(publicKey, signature, onlineTimestampBytes))
return ValidationResult.ONLINE_ACCOUNT_SIGNATURE_INCORRECT;
}
}
return ValidationResult.OK;
}

View File

@ -1,5 +1,7 @@
package org.qortal.data.network;
import java.util.Arrays;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@ -44,4 +46,36 @@ public class OnlineAccountData {
return new PublicKeyAccount(null, this.publicKey).getAddress();
}
// Comparison
@Override
public boolean equals(Object other) {
if (other == this)
return true;
if (!(other instanceof OnlineAccountData))
return false;
OnlineAccountData otherOnlineAccountData = (OnlineAccountData) other;
// Very quick comparison
if (otherOnlineAccountData.timestamp != this.timestamp)
return false;
// Signature more likely to be unique than public key
if (!Arrays.equals(otherOnlineAccountData.signature, this.signature))
return false;
if (!Arrays.equals(otherOnlineAccountData.publicKey, this.publicKey))
return false;
return true;
}
@Override
public int hashCode() {
// Pretty lazy implementation
return (int) this.timestamp;
}
}