mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-11-04 11:06:44 +00:00
add psbt taproot output fields, jade wallet
This commit is contained in:
parent
759ebb975c
commit
9cb95f2f8c
6 changed files with 119 additions and 15 deletions
|
@ -148,10 +148,11 @@ public class PSBT {
|
||||||
for(int outputIndex = 0; outputIndex < outputNodes.size(); outputIndex++) {
|
for(int outputIndex = 0; outputIndex < outputNodes.size(); outputIndex++) {
|
||||||
WalletNode outputNode = outputNodes.get(outputIndex);
|
WalletNode outputNode = outputNodes.get(outputIndex);
|
||||||
if(outputNode == null) {
|
if(outputNode == null) {
|
||||||
PSBTOutput externalRecipientOutput = new PSBTOutput(null, null, Collections.emptyMap(), Collections.emptyMap());
|
PSBTOutput externalRecipientOutput = new PSBTOutput(null, null, null, Collections.emptyMap(), Collections.emptyMap(), null);
|
||||||
psbtOutputs.add(externalRecipientOutput);
|
psbtOutputs.add(externalRecipientOutput);
|
||||||
} else {
|
} else {
|
||||||
TransactionOutput txOutput = transaction.getOutputs().get(outputIndex);
|
TransactionOutput txOutput = transaction.getOutputs().get(outputIndex);
|
||||||
|
Wallet recipientWallet = outputNode.getWallet();
|
||||||
|
|
||||||
//Construct dummy transaction to spend the UTXO created by this wallet's txOutput
|
//Construct dummy transaction to spend the UTXO created by this wallet's txOutput
|
||||||
Transaction transaction = new Transaction();
|
Transaction transaction = new Transaction();
|
||||||
|
@ -168,11 +169,17 @@ public class PSBT {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
for(Keystore keystore : outputNode.getWallet().getKeystores()) {
|
ECKey tapInternalKey = null;
|
||||||
derivedPublicKeys.put(keystore.getPubKey(outputNode), keystore.getKeyDerivation().extend(outputNode.getDerivation()));
|
for(Keystore keystore : recipientWallet.getKeystores()) {
|
||||||
|
derivedPublicKeys.put(recipientWallet.getScriptType().getOutputKey(keystore.getPubKey(outputNode)), keystore.getKeyDerivation().extend(outputNode.getDerivation()));
|
||||||
|
|
||||||
|
//TODO: Implement Musig for multisig wallets
|
||||||
|
if(recipientWallet.getScriptType() == ScriptType.P2TR) {
|
||||||
|
tapInternalKey = keystore.getPubKey(outputNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PSBTOutput walletOutput = new PSBTOutput(redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap());
|
PSBTOutput walletOutput = new PSBTOutput(recipientWallet.getScriptType(), redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap(), tapInternalKey);
|
||||||
psbtOutputs.add(walletOutput);
|
psbtOutputs.add(walletOutput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,7 +483,8 @@ public class PSBT {
|
||||||
for(PSBTInput psbtInput : getPsbtInputs()) {
|
for(PSBTInput psbtInput : getPsbtInputs()) {
|
||||||
List<PSBTEntry> inputEntries = psbtInput.getInputEntries();
|
List<PSBTEntry> inputEntries = psbtInput.getInputEntries();
|
||||||
for(PSBTEntry entry : inputEntries) {
|
for(PSBTEntry entry : inputEntries) {
|
||||||
if(includeXpubs || entry.getKeyType() != PSBT_IN_BIP32_DERIVATION) {
|
if(includeXpubs || (entry.getKeyType() != PSBT_IN_BIP32_DERIVATION && entry.getKeyType() != PSBT_IN_PROPRIETARY
|
||||||
|
&& entry.getKeyType() != PSBT_IN_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_IN_TAP_BIP32_DERIVATION)) {
|
||||||
entry.serializeToStream(baos);
|
entry.serializeToStream(baos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -486,7 +494,9 @@ public class PSBT {
|
||||||
for(PSBTOutput psbtOutput : getPsbtOutputs()) {
|
for(PSBTOutput psbtOutput : getPsbtOutputs()) {
|
||||||
List<PSBTEntry> outputEntries = psbtOutput.getOutputEntries();
|
List<PSBTEntry> outputEntries = psbtOutput.getOutputEntries();
|
||||||
for(PSBTEntry entry : outputEntries) {
|
for(PSBTEntry entry : outputEntries) {
|
||||||
if(includeXpubs || (entry.getKeyType() != PSBT_OUT_REDEEM_SCRIPT && entry.getKeyType() != PSBT_OUT_WITNESS_SCRIPT && entry.getKeyType() != PSBT_OUT_BIP32_DERIVATION && entry.getKeyType() != PSBT_OUT_PROPRIETARY)) {
|
if(includeXpubs || (entry.getKeyType() != PSBT_OUT_REDEEM_SCRIPT && entry.getKeyType() != PSBT_OUT_WITNESS_SCRIPT
|
||||||
|
&& entry.getKeyType() != PSBT_OUT_BIP32_DERIVATION && entry.getKeyType() != PSBT_OUT_PROPRIETARY
|
||||||
|
&& entry.getKeyType() != PSBT_OUT_TAP_INTERNAL_KEY && entry.getKeyType() != PSBT_OUT_TAP_BIP32_DERIVATION)) {
|
||||||
entry.serializeToStream(baos);
|
entry.serializeToStream(baos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,10 +229,12 @@ public class PSBTInput {
|
||||||
ECKey tapPublicKey = ECKey.fromPublicOnly(entry.getKeyData());
|
ECKey tapPublicKey = ECKey.fromPublicOnly(entry.getKeyData());
|
||||||
Map<KeyDerivation, List<Sha256Hash>> tapKeyDerivations = parseTaprootKeyDerivation(entry.getData());
|
Map<KeyDerivation, List<Sha256Hash>> tapKeyDerivations = parseTaprootKeyDerivation(entry.getData());
|
||||||
if(tapKeyDerivations.isEmpty()) {
|
if(tapKeyDerivations.isEmpty()) {
|
||||||
log.warn("PSBT provided an invalid taproot key derivation");
|
log.warn("PSBT provided an invalid input taproot key derivation");
|
||||||
} else {
|
} else {
|
||||||
this.tapDerivedPublicKeys.put(tapPublicKey, tapKeyDerivations);
|
this.tapDerivedPublicKeys.put(tapPublicKey, tapKeyDerivations);
|
||||||
log.debug("Found input taproot key derivation for key " + Utils.bytesToHex(entry.getKey()));
|
for(KeyDerivation tapKeyDerivation : tapKeyDerivations.keySet()) {
|
||||||
|
log.debug("Found input taproot key derivation for key " + Utils.bytesToHex(entry.getKeyData()) + " with master fingerprint " + tapKeyDerivation.getMasterFingerprint() + " at path " + tapKeyDerivation.getDerivationPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PSBT_IN_TAP_INTERNAL_KEY:
|
case PSBT_IN_TAP_INTERNAL_KEY:
|
||||||
|
|
|
@ -4,26 +4,30 @@ import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.Utils;
|
import com.sparrowwallet.drongo.Utils;
|
||||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.protocol.Script;
|
import com.sparrowwallet.drongo.protocol.Script;
|
||||||
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
import com.sparrowwallet.drongo.protocol.Sha256Hash;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
import static com.sparrowwallet.drongo.protocol.ScriptType.*;
|
||||||
import static com.sparrowwallet.drongo.psbt.PSBTEntry.*;
|
import static com.sparrowwallet.drongo.psbt.PSBTEntry.*;
|
||||||
|
|
||||||
public class PSBTOutput {
|
public class PSBTOutput {
|
||||||
public static final byte PSBT_OUT_REDEEM_SCRIPT = 0x00;
|
public static final byte PSBT_OUT_REDEEM_SCRIPT = 0x00;
|
||||||
public static final byte PSBT_OUT_WITNESS_SCRIPT = 0x01;
|
public static final byte PSBT_OUT_WITNESS_SCRIPT = 0x01;
|
||||||
public static final byte PSBT_OUT_BIP32_DERIVATION = 0x02;
|
public static final byte PSBT_OUT_BIP32_DERIVATION = 0x02;
|
||||||
|
public static final byte PSBT_OUT_TAP_INTERNAL_KEY = 0x05;
|
||||||
|
public static final byte PSBT_OUT_TAP_BIP32_DERIVATION = 0x07;
|
||||||
public static final byte PSBT_OUT_PROPRIETARY = (byte)0xfc;
|
public static final byte PSBT_OUT_PROPRIETARY = (byte)0xfc;
|
||||||
|
|
||||||
private Script redeemScript;
|
private Script redeemScript;
|
||||||
private Script witnessScript;
|
private Script witnessScript;
|
||||||
private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
private final Map<String, String> proprietary = new LinkedHashMap<>();
|
private final Map<String, String> proprietary = new LinkedHashMap<>();
|
||||||
|
private Map<ECKey, Map<KeyDerivation, List<Sha256Hash>>> tapDerivedPublicKeys = new LinkedHashMap<>();
|
||||||
|
private ECKey tapInternalKey;
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PSBTOutput.class);
|
private static final Logger log = LoggerFactory.getLogger(PSBTOutput.class);
|
||||||
|
|
||||||
|
@ -31,11 +35,22 @@ public class PSBTOutput {
|
||||||
//empty constructor
|
//empty constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
PSBTOutput(Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary) {
|
PSBTOutput(ScriptType scriptType, Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary, ECKey tapInternalKey) {
|
||||||
this.redeemScript = redeemScript;
|
this.redeemScript = redeemScript;
|
||||||
this.witnessScript = witnessScript;
|
this.witnessScript = witnessScript;
|
||||||
this.derivedPublicKeys.putAll(derivedPublicKeys);
|
|
||||||
|
if(scriptType != P2TR) {
|
||||||
|
this.derivedPublicKeys.putAll(derivedPublicKeys);
|
||||||
|
}
|
||||||
|
|
||||||
this.proprietary.putAll(proprietary);
|
this.proprietary.putAll(proprietary);
|
||||||
|
|
||||||
|
this.tapInternalKey = tapInternalKey;
|
||||||
|
|
||||||
|
if(tapInternalKey != null && !derivedPublicKeys.values().isEmpty()) {
|
||||||
|
KeyDerivation tapKeyDerivation = derivedPublicKeys.values().iterator().next();
|
||||||
|
tapDerivedPublicKeys.put(tapInternalKey, Map.of(tapKeyDerivation, Collections.emptyList()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PSBTOutput(List<PSBTEntry> outputEntries) throws PSBTParseException {
|
PSBTOutput(List<PSBTEntry> outputEntries) throws PSBTParseException {
|
||||||
|
@ -64,6 +79,24 @@ public class PSBTOutput {
|
||||||
proprietary.put(Utils.bytesToHex(entry.getKeyData()), Utils.bytesToHex(entry.getData()));
|
proprietary.put(Utils.bytesToHex(entry.getKeyData()), Utils.bytesToHex(entry.getData()));
|
||||||
log.debug("Found proprietary output " + Utils.bytesToHex(entry.getKeyData()) + ": " + Utils.bytesToHex(entry.getData()));
|
log.debug("Found proprietary output " + Utils.bytesToHex(entry.getKeyData()) + ": " + Utils.bytesToHex(entry.getData()));
|
||||||
break;
|
break;
|
||||||
|
case PSBT_OUT_TAP_INTERNAL_KEY:
|
||||||
|
entry.checkOneByteKey();
|
||||||
|
this.tapInternalKey = ECKey.fromPublicOnly(entry.getData());
|
||||||
|
log.debug("Found output taproot internal key " + Utils.bytesToHex(entry.getData()));
|
||||||
|
break;
|
||||||
|
case PSBT_OUT_TAP_BIP32_DERIVATION:
|
||||||
|
entry.checkOneBytePlusXOnlyPubKey();
|
||||||
|
ECKey tapPublicKey = ECKey.fromPublicOnly(entry.getKeyData());
|
||||||
|
Map<KeyDerivation, List<Sha256Hash>> tapKeyDerivations = parseTaprootKeyDerivation(entry.getData());
|
||||||
|
if(tapKeyDerivations.isEmpty()) {
|
||||||
|
log.warn("PSBT provided an invalid output taproot key derivation");
|
||||||
|
} else {
|
||||||
|
this.tapDerivedPublicKeys.put(tapPublicKey, tapKeyDerivations);
|
||||||
|
for(KeyDerivation tapKeyDerivation : tapKeyDerivations.keySet()) {
|
||||||
|
log.debug("Found output taproot key derivation for key " + Utils.bytesToHex(entry.getKeyData()) + " with master fingerprint " + tapKeyDerivation.getMasterFingerprint() + " at path " + tapKeyDerivation.getDerivationPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("PSBT output not recognized key type: " + entry.getKeyType());
|
log.warn("PSBT output not recognized key type: " + entry.getKeyType());
|
||||||
}
|
}
|
||||||
|
@ -89,6 +122,16 @@ public class PSBTOutput {
|
||||||
entries.add(populateEntry(PSBT_OUT_PROPRIETARY, Utils.hexToBytes(entry.getKey()), Utils.hexToBytes(entry.getValue())));
|
entries.add(populateEntry(PSBT_OUT_PROPRIETARY, Utils.hexToBytes(entry.getKey()), Utils.hexToBytes(entry.getValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(Map.Entry<ECKey, Map<KeyDerivation, List<Sha256Hash>>> entry : tapDerivedPublicKeys.entrySet()) {
|
||||||
|
if(!entry.getValue().isEmpty()) {
|
||||||
|
entries.add(populateEntry(PSBT_OUT_TAP_BIP32_DERIVATION, entry.getKey().getPubKeyXCoord(), serializeTaprootKeyDerivation(Collections.emptyList(), entry.getValue().keySet().iterator().next())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tapInternalKey != null) {
|
||||||
|
entries.add(populateEntry(PSBT_OUT_TAP_INTERNAL_KEY, null, tapInternalKey.getPubKeyXCoord()));
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +146,12 @@ public class PSBTOutput {
|
||||||
|
|
||||||
derivedPublicKeys.putAll(psbtOutput.derivedPublicKeys);
|
derivedPublicKeys.putAll(psbtOutput.derivedPublicKeys);
|
||||||
proprietary.putAll(psbtOutput.proprietary);
|
proprietary.putAll(psbtOutput.proprietary);
|
||||||
|
|
||||||
|
tapDerivedPublicKeys.putAll(psbtOutput.tapDerivedPublicKeys);
|
||||||
|
|
||||||
|
if(psbtOutput.tapInternalKey != null) {
|
||||||
|
tapInternalKey = psbtOutput.tapInternalKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Script getRedeemScript() {
|
public Script getRedeemScript() {
|
||||||
|
@ -132,4 +181,24 @@ public class PSBTOutput {
|
||||||
public Map<String, String> getProprietary() {
|
public Map<String, String> getProprietary() {
|
||||||
return proprietary;
|
return proprietary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<ECKey, Map<KeyDerivation, List<Sha256Hash>>> getTapDerivedPublicKeys() {
|
||||||
|
return tapDerivedPublicKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTapDerivedPublicKeys(Map<ECKey, Map<KeyDerivation, List<Sha256Hash>>> tapDerivedPublicKeys) {
|
||||||
|
this.tapDerivedPublicKeys = tapDerivedPublicKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECKey getTapInternalKey() {
|
||||||
|
return tapInternalKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTapInternalKey(ECKey tapInternalKey) {
|
||||||
|
this.tapInternalKey = tapInternalKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearNonFinalFields() {
|
||||||
|
tapDerivedPublicKeys.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import com.sparrowwallet.drongo.policy.PolicyType;
|
||||||
import com.sparrowwallet.drongo.protocol.*;
|
import com.sparrowwallet.drongo.protocol.*;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||||
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
import com.sparrowwallet.drongo.psbt.PSBTInput;
|
||||||
|
import com.sparrowwallet.drongo.psbt.PSBTOutput;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -1557,6 +1558,8 @@ public class Wallet extends Persistable implements Comparable<Wallet> {
|
||||||
psbtInput.clearNonFinalFields();
|
psbtInput.clearNonFinalFields();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
psbt.getPsbtOutputs().forEach(PSBTOutput::clearNonFinalFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitcoinUnit getAutoUnit() {
|
public BitcoinUnit getAutoUnit() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package com.sparrowwallet.drongo.wallet;
|
package com.sparrowwallet.drongo.wallet;
|
||||||
|
|
||||||
public enum WalletModel {
|
public enum WalletModel {
|
||||||
SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL;
|
SEED, SPARROW, BITCOIN_CORE, ELECTRUM, TREZOR_1, TREZOR_T, COLDCARD, LEDGER_NANO_S, LEDGER_NANO_X, DIGITALBITBOX_01, KEEPKEY, SPECTER_DESKTOP, COBO_VAULT, BITBOX_02, SPECTER_DIY, PASSPORT, BLUE_WALLET, KEYSTONE, SEEDSIGNER, CARAVAN, GORDIAN_SEED_TOOL, JADE;
|
||||||
|
|
||||||
public static WalletModel getModel(String model) {
|
public static WalletModel getModel(String model) {
|
||||||
return valueOf(model.toUpperCase());
|
return valueOf(model.toUpperCase());
|
||||||
|
|
|
@ -11,6 +11,9 @@ import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class PSBTTest {
|
public class PSBTTest {
|
||||||
|
|
||||||
@Test(expected = PSBTParseException.class)
|
@Test(expected = PSBTParseException.class)
|
||||||
|
@ -379,6 +382,23 @@ public class PSBTTest {
|
||||||
Assert.assertFalse(PSBT.isPSBT("x"));
|
Assert.assertFalse(PSBT.isPSBT("x"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTaproot() throws PSBTParseException {
|
||||||
|
Network.set(Network.TESTNET);
|
||||||
|
String strSignedPsbt = "cHNidP8BAH0CAAAAAdPUSBYKaQKOqAMgU2IcGuM6z7JtbkLe69OmYZoa4UxYAAAAAADmdQAAAp4CAAAAAAAAFgAUg+/zyGWbtKbIJb8ZasbGYDtItZhgrgEAAAAAACJRIJMQKWeQsI/WiRS+lmeeyeJaKFVnlVoBtXeuGTO7XIbrAAAAAE8BBDWHzwM27GqkgAAAAO1YZge2AP67ozhdoF9wgg2hpJw1jbVEXLKfxRQUNGEIAlog/wK83w7jxD37prhWrPenLxjGAJzkJKrj6h0ZPK8WED/ZeB1WAACAAQAAgAAAAIAAAQCJAgAAAAGBuBuu5OIheS4SKtYJufScCJDTWWLopBoXtFWhPDuRWQEAAAAA/f///wKNsQEAAAAAACJRIAjXFSnHwcD+J/obgd9CxVneHsUyFKM9xU7NY5K3DgCxHwIAAAAAAAAiUSAhUe66hJMCB1esHqXtxRVJHmviQ4ZjzFIwDWDPk+1KY6VyIQABASuNsQEAAAAAACJRIAjXFSnHwcD+J/obgd9CxVneHsUyFKM9xU7NY5K3DgCxAQMEAAAAAAETQCG/ZGuefjDVqBhmgVEuV1HbdxoZKDDWWTvTUrq6MJreRzj22k/WcFni6yPn9PGZkptZSNx9waf8ouP28ogJz24hFnRZPMvN82XI+lnim7dRKwFgpHnqiDoMGnIoFoSQRX7bGQA/2XgdVgAAgAEAAIAAAACAAQAAAAIAAAABFyB0WTzLzfNlyPpZ4pu3USsBYKR56og6DBpyKBaEkEV+2wAAIQflpK6JYWolG3K2DU7FU3hlkwSdU/69bglhZxaprqSvyxkAP9l4HVYAAIABAACAAAAAgAEAAAADAAAAAQUg5aSuiWFqJRtytg1OxVN4ZZMEnVP+vW4JYWcWqa6kr8sA";
|
||||||
|
PSBT psbt = PSBT.fromString(strSignedPsbt);
|
||||||
|
|
||||||
|
Assert.assertEquals(0, psbt.getPsbtInputs().get(0).getDerivedPublicKeys().size());
|
||||||
|
Assert.assertEquals("74593ccbcdf365c8fa59e29bb7512b0160a479ea883a0c1a7228168490457edb", Utils.bytesToHex(psbt.getPsbtInputs().get(0).getTapDerivedPublicKeys().keySet().iterator().next().getPubKeyXCoord()));
|
||||||
|
Map<KeyDerivation, List<Sha256Hash>> tapInKeyDerivations = psbt.getPsbtInputs().get(0).getTapDerivedPublicKeys().values().iterator().next();
|
||||||
|
Assert.assertEquals("3fd9781d", tapInKeyDerivations.keySet().iterator().next().getMasterFingerprint());
|
||||||
|
|
||||||
|
Assert.assertEquals(0, psbt.getPsbtOutputs().get(0).getDerivedPublicKeys().size());
|
||||||
|
Assert.assertEquals("e5a4ae89616a251b72b60d4ec553786593049d53febd6e09616716a9aea4afcb", Utils.bytesToHex(psbt.getPsbtOutputs().get(1).getTapDerivedPublicKeys().keySet().iterator().next().getPubKeyXCoord()));
|
||||||
|
Map<KeyDerivation, List<Sha256Hash>> tapOutKeyDerivations = psbt.getPsbtOutputs().get(1).getTapDerivedPublicKeys().values().iterator().next();
|
||||||
|
Assert.assertEquals("3fd9781d", tapOutKeyDerivations.keySet().iterator().next().getMasterFingerprint());
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
Network.set(null);
|
Network.set(null);
|
||||||
|
|
Loading…
Reference in a new issue