store address data on wallet nodes

This commit is contained in:
Craig Raw 2022-07-18 16:11:59 +02:00
parent 9ae1f68dc4
commit 5de3abd362
9 changed files with 41 additions and 64 deletions

View file

@ -43,9 +43,13 @@ public abstract class Address {
public abstract ScriptType getScriptType(); public abstract ScriptType getScriptType();
public abstract Script getOutputScript(); public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
public abstract byte[] getOutputScriptData(); public byte[] getOutputScriptData() {
return data;
}
public abstract String getOutputScriptDataType(); public abstract String getOutputScriptDataType();

View file

@ -24,15 +24,6 @@ public class P2PKAddress extends Address {
return ScriptType.P2PK; return ScriptType.P2PK;
} }
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Public Key"; return "Public Key";

View file

@ -19,16 +19,6 @@ public class P2PKHAddress extends Address {
return ScriptType.P2PKH; return ScriptType.P2PKH;
} }
@Override
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Public Key Hash"; return "Public Key Hash";

View file

@ -20,16 +20,6 @@ public class P2SHAddress extends Address {
return ScriptType.P2SH; return ScriptType.P2SH;
} }
@Override
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Script Hash"; return "Script Hash";

View file

@ -25,16 +25,6 @@ public class P2TRAddress extends Address {
return ScriptType.P2TR; return ScriptType.P2TR;
} }
@Override
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Taproot"; return "Taproot";

View file

@ -25,16 +25,6 @@ public class P2WPKHAddress extends Address {
return ScriptType.P2WPKH; return ScriptType.P2WPKH;
} }
@Override
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Witness Public Key Hash"; return "Witness Public Key Hash";

View file

@ -23,16 +23,6 @@ public class P2WSHAddress extends Address {
return ScriptType.P2WSH; return ScriptType.P2WSH;
} }
@Override
public Script getOutputScript() {
return getScriptType().getOutputScript(data);
}
@Override
public byte[] getOutputScriptData() {
return data;
}
@Override @Override
public String getOutputScriptDataType() { public String getOutputScriptDataType() {
return "Witness Script Hash"; return "Witness Script Hash";

View file

@ -31,7 +31,10 @@ public class Keystore extends Persistable {
private DeterministicSeed seed; private DeterministicSeed seed;
//For BIP47 keystores - not persisted but must be unencrypted to generate keys //For BIP47 keystores - not persisted but must be unencrypted to generate keys
private ExtendedKey bip47ExtendedPrivateKey; private transient ExtendedKey bip47ExtendedPrivateKey;
//Avoid performing repeated expensive seed derivation checks
private transient boolean extendedPublicKeyChecked;
public Keystore() { public Keystore() {
this(DEFAULT_LABEL); this(DEFAULT_LABEL);
@ -83,6 +86,7 @@ public class Keystore extends Persistable {
public void setExtendedPublicKey(ExtendedKey extendedPublicKey) { public void setExtendedPublicKey(ExtendedKey extendedPublicKey) {
this.extendedPublicKey = extendedPublicKey; this.extendedPublicKey = extendedPublicKey;
this.extendedPublicKeyChecked = false;
} }
public PaymentCode getExternalPaymentCode() { public PaymentCode getExternalPaymentCode() {
@ -125,6 +129,14 @@ public class Keystore extends Persistable {
return hasMasterPrivateKey() || (source == KeystoreSource.SW_PAYMENT_CODE && bip47ExtendedPrivateKey != null); return hasMasterPrivateKey() || (source == KeystoreSource.SW_PAYMENT_CODE && bip47ExtendedPrivateKey != null);
} }
public boolean needsPassphrase() {
if(seed != null) {
return seed.needsPassphrase();
}
return false;
}
public PaymentCode getPaymentCode() { public PaymentCode getPaymentCode() {
DeterministicKey bip47Key = bip47ExtendedPrivateKey.getKey(); DeterministicKey bip47Key = bip47ExtendedPrivateKey.getKey();
return new PaymentCode(bip47Key.getPubKey(), bip47Key.getChainCode()); return new PaymentCode(bip47Key.getPubKey(), bip47Key.getChainCode());
@ -278,7 +290,7 @@ public class Keystore extends Persistable {
throw new InvalidKeystoreException("Source of " + source + " but no seed or master private key is present"); throw new InvalidKeystoreException("Source of " + source + " but no seed or master private key is present");
} }
if((seed != null && !seed.isEncrypted()) || (masterPrivateExtendedKey != null && !masterPrivateExtendedKey.isEncrypted())) { if(!extendedPublicKeyChecked && ((seed != null && !seed.isEncrypted()) || (masterPrivateExtendedKey != null && !masterPrivateExtendedKey.isEncrypted()))) {
try { try {
List<ChildNumber> derivation = getKeyDerivation().getDerivation(); List<ChildNumber> derivation = getKeyDerivation().getDerivation();
DeterministicKey derivedKey = getExtendedMasterPrivateKey().getKey(derivation); DeterministicKey derivedKey = getExtendedMasterPrivateKey().getKey(derivation);
@ -287,6 +299,7 @@ public class Keystore extends Persistable {
if(!xpub.equals(getExtendedPublicKey())) { if(!xpub.equals(getExtendedPublicKey())) {
throw new InvalidKeystoreException("Specified extended public key does not match public key derived from seed"); throw new InvalidKeystoreException("Specified extended public key does not match public key derived from seed");
} }
extendedPublicKeyChecked = true;
} catch(MnemonicException e) { } catch(MnemonicException e) {
throw new InvalidKeystoreException("Invalid mnemonic specified for seed", e); throw new InvalidKeystoreException("Invalid mnemonic specified for seed", e);
} }

View file

@ -13,6 +13,7 @@ import java.util.stream.Collectors;
public class WalletNode extends Persistable implements Comparable<WalletNode> { public class WalletNode extends Persistable implements Comparable<WalletNode> {
private final String derivationPath; private final String derivationPath;
private String label; private String label;
private Address address;
private TreeSet<WalletNode> children = new TreeSet<>(); private TreeSet<WalletNode> children = new TreeSet<>();
private TreeSet<BlockTransactionHashIndex> transactionOutputs = new TreeSet<>(); private TreeSet<BlockTransactionHashIndex> transactionOutputs = new TreeSet<>();
@ -267,11 +268,28 @@ public class WalletNode extends Persistable implements Comparable<WalletNode> {
} }
public Address getAddress() { public Address getAddress() {
if(address != null) {
return address;
}
if(wallet.getKeystores().stream().noneMatch(Keystore::needsPassphrase)) {
address = wallet.getAddress(this);
return address;
}
return wallet.getAddress(this); return wallet.getAddress(this);
} }
public byte[] getAddressData() {
return address == null ? null : address.getData();
}
public void setAddress(Address address) {
this.address = address;
}
public Script getOutputScript() { public Script getOutputScript() {
return wallet.getOutputScript(this); return getAddress().getOutputScript();
} }
public String getOutputDescriptor() { public String getOutputDescriptor() {
@ -324,6 +342,7 @@ public class WalletNode extends Persistable implements Comparable<WalletNode> {
WalletNode copy = new WalletNode(walletCopy, derivationPath); WalletNode copy = new WalletNode(walletCopy, derivationPath);
copy.setId(getId()); copy.setId(getId());
copy.setLabel(label); copy.setLabel(label);
copy.setAddress(address);
for(WalletNode child : getChildren()) { for(WalletNode child : getChildren()) {
copy.children.add(child.copy(walletCopy)); copy.children.add(child.copy(walletCopy));