Browse Source

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.
split-DB
catbref 4 years ago
parent
commit
8dbd8c4e65
  1. 20
      src/main/java/org/qortal/block/Block.java
  2. 34
      src/main/java/org/qortal/data/network/OnlineAccountData.java

20
src/main/java/org/qortal/block/Block.java

@ -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;
}

34
src/main/java/org/qortal/data/network/OnlineAccountData.java

@ -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;
}
}

Loading…
Cancel
Save