Java Code Examples for org.bitcoinj.core.ECKey#MissingPrivateKeyException

The following examples show how to use org.bitcoinj.core.ECKey#MissingPrivateKeyException . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: DeterministicKeyChainTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void watchingChain() throws UnreadableWalletException {
    Utils.setMockClock();
    DeterministicKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    DeterministicKey key4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);

    DeterministicKey watchingKey = chain.getWatchingKey();
    final String pub58 = watchingKey.serializePubB58(MAINNET);
    assertEquals("xpub69KR9epSNBM59KLuasxMU5CyKytMJjBP5HEZ5p8YoGUCpM6cM9hqxB9DDPCpUUtqmw5duTckvPfwpoWGQUFPmRLpxs5jYiTf2u6xRMcdhDf", pub58);
    watchingKey = DeterministicKey.deserializeB58(null, pub58, MAINNET);
    watchingKey.setCreationTimeSeconds(100000);
    chain = DeterministicKeyChain.watch(watchingKey);
    assertEquals(100000, chain.getEarliestKeyCreationTime());
    chain.setLookaheadSize(10);
    chain.maybeLookAhead();

    assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint());
    try {
        // Can't sign with a key from a watching chain.
        key.sign(Sha256Hash.ZERO_HASH);
        fail();
    } catch (ECKey.MissingPrivateKeyException e) {
        // Ignored.
    }
    // Test we can serialize and deserialize a watching chain OK.
    List<Protos.Key> serialization = chain.serializeToProtobuf();
    checkSerialization(serialization, "watching-wallet-serialization.txt");
    chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
    final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
 
Example 2
Source File: DeterministicKeyChainTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void watchingChainArbitraryPath() throws UnreadableWalletException {
    Utils.setMockClock();
    DeterministicKey key1 = bip44chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = bip44chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = bip44chain.getKey(KeyChain.KeyPurpose.CHANGE);
    DeterministicKey key4 = bip44chain.getKey(KeyChain.KeyPurpose.CHANGE);

    DeterministicKey watchingKey = bip44chain.getWatchingKey();
    watchingKey = watchingKey.dropPrivateBytes().dropParent();
    watchingKey.setCreationTimeSeconds(100000);
    chain = DeterministicKeyChain.watch(watchingKey);
    assertEquals(100000, chain.getEarliestKeyCreationTime());
    chain.setLookaheadSize(10);
    chain.maybeLookAhead();

    assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint());
    try {
        // Can't sign with a key from a watching chain.
        key.sign(Sha256Hash.ZERO_HASH);
        fail();
    } catch (ECKey.MissingPrivateKeyException e) {
        // Ignored.
    }
    // Test we can serialize and deserialize a watching chain OK.
    List<Protos.Key> serialization = chain.serializeToProtobuf();
    checkSerialization(serialization, "watching-wallet-arbitrary-path-serialization.txt");
    chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
    final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
 
Example 3
Source File: DeterministicKeyChainTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void watchingChainAccountOne() throws UnreadableWalletException {
    Utils.setMockClock();
    DeterministicKeyChain chain1 = new AccountOneChain(chain.getKeyCrypter(), chain.getSeed());
    DeterministicKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);
    DeterministicKey key4 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);

    DeterministicKey watchingKey = chain1.getWatchingKey();
    final String pub58 = watchingKey.serializePubB58(MAINNET);
    assertEquals("xpub69KR9epJ2Wp6ywiv4Xu5WfBUpX4GLu6D5NUMd4oUkCFoZoRNyk3ZCxfKPDkkGvCPa16dPgEdY63qoyLqEa5TQQy1nmfSmgWcagRzimyV7uA", pub58);
    watchingKey = DeterministicKey.deserializeB58(null, pub58, MAINNET);
    watchingKey.setCreationTimeSeconds(100000);
    chain = DeterministicKeyChain.watch(watchingKey);
    assertEquals(100000, chain.getEarliestKeyCreationTime());
    chain.setLookaheadSize(10);
    chain.maybeLookAhead();

    assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint());
    try {
        // Can't sign with a key from a watching chain.
        key.sign(Sha256Hash.ZERO_HASH);
        fail();
    } catch (ECKey.MissingPrivateKeyException e) {
        // Ignored.
    }
    // Test we can serialize and deserialize a watching chain OK.
    List<Protos.Key> serialization = chain.serializeToProtobuf();
    checkSerialization(serialization, "watching-wallet-serialization-account-one.txt");
    chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
    final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
 
Example 4
Source File: DeterministicKeyChainTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test
public void spendingChain() throws UnreadableWalletException {
    Utils.setMockClock();
    DeterministicKey key1 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    DeterministicKey key4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);

    NetworkParameters params = MainNetParams.get();
    DeterministicKey watchingKey = chain.getWatchingKey();
    final String prv58 = watchingKey.serializePrivB58(params);
    assertEquals("xprv9vL4k9HYXonmvqGSUrRM6wGEmx3ruGTXi4JxHRiwEvwDwYmTocPbQNpjN89gpqPrFofmfvALwgnNFBCH2grse1YDf8ERAwgdvbjRtoMfsbV", prv58);
    watchingKey = DeterministicKey.deserializeB58(null, prv58, params);
    watchingKey.setCreationTimeSeconds(100000);
    chain = DeterministicKeyChain.spend(watchingKey);
    assertEquals(100000, chain.getEarliestKeyCreationTime());
    chain.setLookaheadSize(10);
    chain.maybeLookAhead();

    assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint());
    try {
        // We can sign with a key from a spending chain.
        key.sign(Sha256Hash.ZERO_HASH);
    } catch (ECKey.MissingPrivateKeyException e) {
        fail();
    }
    // Test we can serialize and deserialize a watching chain OK.
    List<Protos.Key> serialization = chain.serializeToProtobuf();
    checkSerialization(serialization, "spending-wallet-serialization.txt");
    chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
    final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
 
Example 5
Source File: DeterministicKeyChainTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
/**
 * verifySpendableKeyChain
 * <p>
 * firstReceiveKey and secondReceiveKey are the first two keys of the external chain of a known key chain
 * firstChangeKey and secondChangeKey are the first two keys of the internal chain of a known key chain
 * keyChain is a DeterministicKeyChain loaded from a serialized format or derived in some other way from
 * the known key chain
 * <p>
 * This method verifies that known keys match a newly created keyChain and that keyChain's protobuf
 * matches the serializationFile.
 */
private void verifySpendableKeyChain(DeterministicKey firstReceiveKey, DeterministicKey secondReceiveKey,
                                     DeterministicKey firstChangeKey, DeterministicKey secondChangeKey,
                                     DeterministicKeyChain keyChain, String serializationFile) throws UnreadableWalletException {

    //verify that the keys are the same as the keyChain
    assertEquals(firstReceiveKey.getPubKeyPoint(), keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    assertEquals(secondReceiveKey.getPubKeyPoint(), keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
    final DeterministicKey key = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(firstChangeKey.getPubKeyPoint(), key.getPubKeyPoint());

    try {
        key.sign(Sha256Hash.ZERO_HASH);
    } catch (ECKey.MissingPrivateKeyException e) {
        // We can sign with a key from a spending chain.
        fail();
    }

    // Test we can serialize and deserialize the chain OK
    List<Protos.Key> serialization = keyChain.serializeToProtobuf();
    checkSerialization(serialization, serializationFile);

    // Check that the second change key matches after loading from the serialization, serializing and deserializing
    long secs = keyChain.getEarliestKeyCreationTime();
    keyChain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
    serialization = keyChain.serializeToProtobuf();
    checkSerialization(serialization, serializationFile);
    assertEquals(secs, keyChain.getEarliestKeyCreationTime());
    final DeterministicKey nextChangeKey = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(secondChangeKey.getPubKeyPoint(), nextChangeKey.getPubKeyPoint());
}
 
Example 6
Source File: WalletTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test(expected = ECKey.MissingPrivateKeyException.class)
public void watchingWalletWithCreationTime() throws Exception {
    DeterministicKey watchKey = wallet.getWatchingKey();
    String serialized = watchKey.serializePubB58(UNITTEST);
    Wallet watchingWallet = Wallet.fromWatchingKeyB58(UNITTEST, serialized, 1415282801);
    DeterministicKey key2 = watchingWallet.freshReceiveKey();
    assertEquals(myKey, key2);

    ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key, key2);
    key.sign(Sha256Hash.ZERO_HASH);
    key2.sign(Sha256Hash.ZERO_HASH);
}
 
Example 7
Source File: WalletTest.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
@Test(expected = ECKey.MissingPrivateKeyException.class)
public void completeTxPartiallySignedThrows() throws Exception {
    sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, wallet.freshReceiveKey());
    SendRequest req = SendRequest.emptyWallet(OTHER_ADDRESS);
    wallet.completeTx(req);
    // Delete the sigs
    for (TransactionInput input : req.tx.getInputs())
        input.clearScriptBytes();
    Wallet watching = Wallet.fromWatchingKey(UNITTEST, wallet.getWatchingKey().dropParent().dropPrivateBytes());
    watching.completeTx(SendRequest.forTx(req.tx));
}
 
Example 8
Source File: WalletTest.java    From green_android with GNU General Public License v3.0 5 votes vote down vote up
@Test(expected = ECKey.MissingPrivateKeyException.class)
public void watchingWalletWithCreationTime() throws Exception {
    DeterministicKey watchKey = wallet.getWatchingKey();
    String serialized = watchKey.serializePubB58(PARAMS);
    Wallet watchingWallet = Wallet.fromWatchingKeyB58(PARAMS, serialized, 1415282801);
    DeterministicKey key2 = watchingWallet.freshReceiveKey();
    assertEquals(myKey, key2);

    ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key, key2);
    key.sign(Sha256Hash.ZERO_HASH);
    key2.sign(Sha256Hash.ZERO_HASH);
}
 
Example 9
Source File: WalletTest.java    From green_android with GNU General Public License v3.0 5 votes vote down vote up
@Test (expected = ECKey.MissingPrivateKeyException.class)
public void completeTxPartiallySignedThrows() throws Exception {
    sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, wallet.freshReceiveKey());
    SendRequest req = SendRequest.emptyWallet(OTHER_ADDRESS);
    wallet.completeTx(req);
    // Delete the sigs
    for (TransactionInput input : req.tx.getInputs())
        input.clearScriptBytes();
    Wallet watching = Wallet.fromWatchingKey(PARAMS, wallet.getWatchingKey().dropParent().dropPrivateBytes());
    watching.completeTx(SendRequest.forTx(req.tx));
}
 
Example 10
Source File: WalletTest.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
@Test(expected = ECKey.MissingPrivateKeyException.class)
public void watchingWalletWithCreationTime() throws Exception {
    DeterministicKey watchKey = wallet.getWatchingKey();
    String serialized = watchKey.serializePubB58(PARAMS);
    Wallet watchingWallet = Wallet.fromWatchingKeyB58(PARAMS, serialized, 1415282801);
    DeterministicKey key2 = watchingWallet.freshReceiveKey();
    assertEquals(myKey, key2);

    ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE);
    assertEquals(key, key2);
    key.sign(Sha256Hash.ZERO_HASH);
    key2.sign(Sha256Hash.ZERO_HASH);
}
 
Example 11
Source File: WalletTest.java    From GreenBits with GNU General Public License v3.0 5 votes vote down vote up
@Test (expected = ECKey.MissingPrivateKeyException.class)
public void completeTxPartiallySignedThrows() throws Exception {
    sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, wallet.freshReceiveKey());
    SendRequest req = SendRequest.emptyWallet(OTHER_ADDRESS);
    wallet.completeTx(req);
    // Delete the sigs
    for (TransactionInput input : req.tx.getInputs())
        input.clearScriptBytes();
    Wallet watching = Wallet.fromWatchingKey(PARAMS, wallet.getWatchingKey().dropParent().dropPrivateBytes());
    watching.completeTx(SendRequest.forTx(req.tx));
}
 
Example 12
Source File: MissingSigResolutionSigner.java    From bcm-android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public boolean signInputs(ProposedTransaction propTx, KeyBag keyBag) {
    if (missingSigsMode == Wallet.MissingSigsMode.USE_OP_ZERO)
        return true;

    int numInputs = propTx.partialTx.getInputs().size();
    byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin();
    for (int i = 0; i < numInputs; i++) {
        TransactionInput txIn = propTx.partialTx.getInput(i);
        if (txIn.getConnectedOutput() == null) {
            log.warn("Missing connected output, assuming input {} is already signed.", i);
            continue;
        }

        Script scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
        Script inputScript = txIn.getScriptSig();
        if (ScriptPattern.isPayToScriptHash(scriptPubKey) || ScriptPattern.isSentToMultisig(scriptPubKey)) {
            int sigSuffixCount = ScriptPattern.isPayToScriptHash(scriptPubKey) ? 1 : 0;
            // all chunks except the first one (OP_0) and the last (redeem script) are signatures
            for (int j = 1; j < inputScript.getChunks().size() - sigSuffixCount; j++) {
                ScriptChunk scriptChunk = inputScript.getChunks().get(j);
                if (scriptChunk.equalsOpCode(0)) {
                    if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                        throw new MissingSignatureException();
                    } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                        txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, j - 1));
                    }
                }
            }
        } else {
            if (inputScript.getChunks().get(0).equalsOpCode(0)) {
                if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                    throw new ECKey.MissingPrivateKeyException();
                } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                    txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, 0));
                }
            }
        }
        // TODO handle non-P2SH multisig
    }
    return true;
}
 
Example 13
Source File: MissingSigResolutionSigner.java    From green_android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public boolean signInputs(ProposedTransaction propTx, KeyBag keyBag) {
    if (missingSigsMode == Wallet.MissingSigsMode.USE_OP_ZERO)
        return true;

    int numInputs = propTx.partialTx.getInputs().size();
    byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin();
    for (int i = 0; i < numInputs; i++) {
        TransactionInput txIn = propTx.partialTx.getInput(i);
        if (txIn.getConnectedOutput() == null) {
            log.warn("Missing connected output, assuming input {} is already signed.", i);
            continue;
        }

        Script scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
        Script inputScript = txIn.getScriptSig();
        if (scriptPubKey.isPayToScriptHash() || scriptPubKey.isSentToMultiSig()) {
            int sigSuffixCount = scriptPubKey.isPayToScriptHash() ? 1 : 0;
            // all chunks except the first one (OP_0) and the last (redeem script) are signatures
            for (int j = 1; j < inputScript.getChunks().size() - sigSuffixCount; j++) {
                ScriptChunk scriptChunk = inputScript.getChunks().get(j);
                if (scriptChunk.equalsOpCode(0)) {
                    if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                        throw new MissingSignatureException();
                    } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                        txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, j - 1));
                    }
                }
            }
        } else {
            if (inputScript.getChunks().get(0).equalsOpCode(0)) {
                if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                    throw new ECKey.MissingPrivateKeyException();
                } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                    txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, 0));
                }
            }
        }
        // TODO handle non-P2SH multisig
    }
    return true;
}
 
Example 14
Source File: MissingSigResolutionSigner.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
@Override
public boolean signInputs(ProposedTransaction propTx, KeyBag keyBag) {
    if (missingSigsMode == Wallet.MissingSigsMode.USE_OP_ZERO)
        return true;

    int numInputs = propTx.partialTx.getInputs().size();
    byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin();
    for (int i = 0; i < numInputs; i++) {
        TransactionInput txIn = propTx.partialTx.getInput(i);
        if (txIn.getConnectedOutput() == null) {
            log.warn("Missing connected output, assuming input {} is already signed.", i);
            continue;
        }

        Script scriptPubKey = txIn.getConnectedOutput().getScriptPubKey();
        Script inputScript = txIn.getScriptSig();
        if (scriptPubKey.isPayToScriptHash() || scriptPubKey.isSentToMultiSig()) {
            int sigSuffixCount = scriptPubKey.isPayToScriptHash() ? 1 : 0;
            // all chunks except the first one (OP_0) and the last (redeem script) are signatures
            for (int j = 1; j < inputScript.getChunks().size() - sigSuffixCount; j++) {
                ScriptChunk scriptChunk = inputScript.getChunks().get(j);
                if (scriptChunk.equalsOpCode(0)) {
                    if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                        throw new MissingSignatureException();
                    } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                        txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, j - 1));
                    }
                }
            }
        } else {
            if (inputScript.getChunks().get(0).equalsOpCode(0)) {
                if (missingSigsMode == Wallet.MissingSigsMode.THROW) {
                    throw new ECKey.MissingPrivateKeyException();
                } else if (missingSigsMode == Wallet.MissingSigsMode.USE_DUMMY_SIG) {
                    txIn.setScriptSig(scriptPubKey.getScriptSigWithSignature(inputScript, dummySig, 0));
                }
            }
        }
        // TODO handle non-P2SH multisig
    }
    return true;
}