improve invalid wallet error messaging, fix public psbt

This commit is contained in:
Craig Raw 2020-11-04 12:09:17 +02:00
parent 9c9836147a
commit 3433c5f205
6 changed files with 107 additions and 27 deletions

View file

@ -533,16 +533,15 @@ public class PSBT {
try {
PSBT publicCopy = new PSBT(serialize());
publicCopy.extendedPublicKeys.clear();
publicCopy.globalProprietary.clear();
for(PSBTInput psbtInput : publicCopy.getPsbtInputs()) {
psbtInput.clearPrivateFields();
psbtInput.getDerivedPublicKeys().clear();
psbtInput.getProprietary().clear();
}
for(PSBTOutput psbtOutput : publicCopy.getPsbtOutputs()) {
psbtOutput.getDerivedPublicKeys().clear();
psbtOutput.getProprietary().clear();
}
if(publicCopy.isFinalized()) {
publicCopy.transaction = publicCopy.extractTransaction();
}
return publicCopy;
} catch(PSBTParseException e) {

View file

@ -538,7 +538,7 @@ public class PSBTInput {
return getWitnessUtxo() != null ? getWitnessUtxo() : (getNonWitnessUtxo() != null ? getNonWitnessUtxo().getOutputs().get(vout) : null);
}
public void clearPrivateFields() {
public void clearNonFinalFields() {
partialSignatures.clear();
sigHash = null;
redeemScript = null;

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.drongo.wallet;
public class InvalidKeystoreException extends Exception {
public InvalidKeystoreException() {
super();
}
public InvalidKeystoreException(String msg) {
super(msg);
}
public InvalidKeystoreException(String msg, Throwable throwable) {
super(msg, throwable);
}
}

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.drongo.wallet;
public class InvalidWalletException extends Exception {
public InvalidWalletException() {
super();
}
public InvalidWalletException(String msg) {
super(msg);
}
public InvalidWalletException(String msg, Throwable throwable) {
super(msg, throwable);
}
}

View file

@ -130,25 +130,55 @@ public class Keystore {
}
public boolean isValid() {
if(label == null || source == null || walletModel == null || keyDerivation == null || extendedPublicKey == null) {
try {
checkKeystore();
} catch(InvalidKeystoreException e) {
return false;
}
if(label.isEmpty() || label.replace(" ", "").length() > 16) {
return false;
return true;
}
public void checkKeystore() throws InvalidKeystoreException {
if(label == null) {
throw new InvalidKeystoreException("No label specified");
}
if(source == null) {
throw new InvalidKeystoreException("No source specified");
}
if(walletModel == null) {
throw new InvalidKeystoreException("No wallet model specified");
}
if(keyDerivation == null) {
throw new InvalidKeystoreException("No key derivation specified");
}
if(extendedPublicKey == null) {
throw new InvalidKeystoreException("No extended public key specified");
}
if(label.isEmpty()) {
throw new InvalidKeystoreException("Label too short");
}
if(label.replace(" ", "").length() > 16) {
throw new InvalidKeystoreException("Label too long");
}
if(keyDerivation.getDerivationPath() == null || keyDerivation.getDerivationPath().isEmpty() || !KeyDerivation.isValid(keyDerivation.getDerivationPath())) {
return false;
throw new InvalidKeystoreException("Invalid key derivation path of " + keyDerivation.getDerivationPath());
}
if(keyDerivation.getMasterFingerprint() == null || keyDerivation.getMasterFingerprint().length() != 8 || !Utils.isHex(keyDerivation.getMasterFingerprint())) {
return false;
throw new InvalidKeystoreException("Invalid master fingerprint of " + keyDerivation.getMasterFingerprint());
}
if(source == KeystoreSource.SW_SEED) {
if(seed == null) {
return false;
throw new InvalidKeystoreException("Source of " + source + " but no seed is present");
}
if(!seed.isEncrypted()) {
@ -158,15 +188,13 @@ public class Keystore {
DeterministicKey derivedKeyPublicOnly = derivedKey.dropPrivateBytes().dropParent();
ExtendedKey xpub = new ExtendedKey(derivedKeyPublicOnly, derivedKey.getParentFingerprint(), derivation.isEmpty() ? ChildNumber.ZERO : derivation.get(derivation.size() - 1));
if(!xpub.equals(getExtendedPublicKey())) {
return false;
throw new InvalidKeystoreException("Specified extended public key does not match public key derived from seed");
}
} catch(MnemonicException e) {
return false;
throw new InvalidKeystoreException("Invalid mnemonic specified for seed", e);
}
}
}
return true;
}
public Keystore copy() {

View file

@ -764,7 +764,7 @@ public class Wallet {
psbtInput.setFinalScriptSig(finalizedTxInput.getScriptSig());
psbtInput.setFinalScriptWitness(finalizedTxInput.getWitness());
psbtInput.clearPrivateFields();
psbtInput.clearNonFinalFields();
}
}
}
@ -799,43 +799,66 @@ public class Wallet {
}
public boolean isValid() {
if(policyType == null || scriptType == null || defaultPolicy == null || keystores.isEmpty()) {
try {
checkWallet();
} catch(InvalidWalletException e) {
return false;
}
return true;
}
public void checkWallet() throws InvalidWalletException {
if(policyType == null) {
throw new InvalidWalletException("No policy type specified");
}
if(scriptType == null) {
throw new InvalidWalletException("No script type specified");
}
if(defaultPolicy == null) {
throw new InvalidWalletException("No default policy specified");
}
if(keystores.isEmpty()) {
throw new InvalidWalletException("No keystores specified");
}
if(!ScriptType.getScriptTypesForPolicyType(policyType).contains(scriptType)) {
return false;
throw new InvalidWalletException("Script type of " + scriptType + " is not valid for a policy type of " + policyType);
}
int numSigs;
try {
numSigs = defaultPolicy.getNumSignaturesRequired();
} catch (Exception e) {
return false;
throw new InvalidWalletException("Cannot determine number of required signatures to sign a transaction");
}
if(policyType.equals(PolicyType.SINGLE) && (numSigs != 1 || keystores.size() != 1)) {
return false;
throw new InvalidWalletException(policyType + " wallet needs " + numSigs + " and has " + keystores.size() + " keystores");
}
if(policyType.equals(PolicyType.MULTI) && (numSigs < 1 || numSigs > keystores.size())) {
return false;
throw new InvalidWalletException(policyType + " wallet needs " + numSigs + " and has " + keystores.size() + " keystores");
}
if(containsDuplicateKeystoreLabels()) {
return false;
throw new InvalidWalletException("Wallet keystores have duplicate labels");
}
for(Keystore keystore : keystores) {
if(!keystore.isValid()) {
return false;
}
if(derivationMatchesAnotherScriptType(keystore.getKeyDerivation().getDerivationPath())) {
return false;
}
try {
keystore.checkKeystore();
} catch(InvalidKeystoreException e) {
throw new InvalidWalletException("Keystore " + keystore.getLabel() + " is invalid (" + e.getMessage() + ")", e);
}
return true;
if(derivationMatchesAnotherScriptType(keystore.getKeyDerivation().getDerivationPath())) {
throw new InvalidWalletException("Keystore " + keystore.getLabel() + " derivation of " + keystore.getKeyDerivation().getDerivationPath() + " in " + scriptType.getName() + " wallet matches another default script type.");
}
}
}
public boolean derivationMatchesAnotherScriptType(String derivationPath) {