예제 #1
0
 /// <summary>
 /// parse output descriptor.
 /// </summary>
 /// <param name="descriptorString">output descriptor</param>
 /// <param name="network">network type for address</param>
 public Descriptor(string descriptorString, CfdNetworkType network)
 {
     if (descriptorString is null)
     {
         throw new ArgumentNullException(nameof(descriptorString));
     }
     using (var handle = new ErrorHandle())
     {
         descriptor = GetDescriptorChecksum(handle, descriptorString, network);
         scriptList = ParseDescriptor(handle, descriptorString, "", network);
         rootData   = AnalyzeScriptList(scriptList);
     }
 }
예제 #2
0
 public CfdDescriptorScriptData[] GetList()
 {
     CfdDescriptorScriptData[] newList = new CfdDescriptorScriptData[scriptList.Length];
     scriptList.CopyTo(newList, 0);
     return(newList);
 }
예제 #3
0
        private static CfdDescriptorScriptData[] ParseDescriptor(
            ErrorHandle handle, string descriptorString,
            string derivePath, CfdNetworkType network, out CfdDescriptorScriptData rootData)
        {
            var ret = NativeMethods.CfdParseDescriptor(
                handle.GetHandle(), descriptorString, (int)network, derivePath,
                out IntPtr descriptorHandle, out uint maxIndex);

            if (ret != CfdErrorCode.Success)
            {
                handle.ThrowError(ret);
            }
            try
            {
                bool isMultisig = false;
                uint maxKeyNum  = 0;
                uint requireNum = 0;
                {
                    ret = NativeMethods.CfdGetDescriptorRootData(
                        handle.GetHandle(), descriptorHandle,
                        out int scriptType, out IntPtr lockingScript, out IntPtr address,
                        out int hashType, out IntPtr redeemScript,
                        out int keyType, out IntPtr pubkey, out IntPtr extPubkey,
                        out IntPtr extPrivkey, out IntPtr schnorrPubkey, out IntPtr treeString,
                        out isMultisig, out maxKeyNum, out requireNum);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    CCommon.ConvertToString(lockingScript);
                    string tempAddress        = CCommon.ConvertToString(address);
                    string tempRedeemScript   = CCommon.ConvertToString(redeemScript);
                    string tempPubkey         = CCommon.ConvertToString(pubkey);
                    string tempExtPubkey      = CCommon.ConvertToString(extPubkey);
                    string tempExtPrivkey     = CCommon.ConvertToString(extPrivkey);
                    string tempSchnorr        = CCommon.ConvertToString(schnorrPubkey);
                    string tempTreeStr        = CCommon.ConvertToString(treeString);
                    CfdDescriptorKeyType type = (CfdDescriptorKeyType)keyType;
                    CfdKeyData           keyData;
                    TapBranch            scriptTree = new TapBranch();
                    if (type == CfdDescriptorKeyType.Bip32)
                    {
                        keyData = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                    }
                    else if (type == CfdDescriptorKeyType.Bip32Priv)
                    {
                        keyData = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                    }
                    else if (type == CfdDescriptorKeyType.SchnorrPubkey)
                    {
                        keyData = new CfdKeyData(new SchnorrPubkey(tempSchnorr));
                    }
                    else if (type == CfdDescriptorKeyType.Public)
                    {
                        keyData = new CfdKeyData(new Pubkey(tempPubkey));
                    }
                    else
                    {
                        keyData = new CfdKeyData();
                    }
                    Address addr = new Address();
                    if (tempAddress.Length > 0)
                    {
                        addr = new Address(tempAddress);
                    }
                    if (tempTreeStr.Length > 0)
                    {
                        scriptTree = new TapBranch(tempTreeStr);
                    }
                    rootData = new CfdDescriptorScriptData((CfdDescriptorScriptType)scriptType, 0,
                                                           (CfdHashType)hashType, addr, new Script(tempRedeemScript),
                                                           scriptTree, keyData, Array.Empty <CfdKeyData>(), 0);
                }
                CfdDescriptorScriptData[] list = new CfdDescriptorScriptData[maxIndex + 1];
                for (uint index = 0; index <= maxIndex; ++index)
                {
                    // force initialized because guard illegal memory access.
                    IntPtr lockingScript = IntPtr.Zero;
                    IntPtr redeemScript  = IntPtr.Zero;
                    IntPtr address       = IntPtr.Zero;
                    IntPtr pubkey        = IntPtr.Zero;
                    IntPtr extPubkey     = IntPtr.Zero;
                    IntPtr extPrivkey    = IntPtr.Zero;
                    ret = NativeMethods.CfdGetDescriptorData(
                        handle.GetHandle(), descriptorHandle, index, out _, out uint depth,
                        out int scriptType, out lockingScript, out address,
                        out int hashType, out redeemScript,
                        out int keyType, out pubkey, out extPubkey, out extPrivkey,
                        out isMultisig, out maxKeyNum, out requireNum);
                    if (ret != CfdErrorCode.Success)
                    {
                        handle.ThrowError(ret);
                    }
                    CCommon.ConvertToString(lockingScript);
                    string tempAddress      = CCommon.ConvertToString(address);
                    string tempRedeemScript = CCommon.ConvertToString(redeemScript);
                    string tempPubkey       = CCommon.ConvertToString(pubkey);
                    string tempExtPubkey    = CCommon.ConvertToString(extPubkey);
                    string tempExtPrivkey   = CCommon.ConvertToString(extPrivkey);
                    CfdDescriptorScriptData data;
                    CfdKeyData           keyData;
                    CfdDescriptorKeyType type;
                    switch ((CfdDescriptorScriptType)scriptType)
                    {
                    case CfdDescriptorScriptType.Combo:
                    case CfdDescriptorScriptType.Pk:
                    case CfdDescriptorScriptType.Pkh:
                    case CfdDescriptorScriptType.Wpkh:
                    case CfdDescriptorScriptType.Taproot:
                        type = (CfdDescriptorKeyType)keyType;
                        if (type == CfdDescriptorKeyType.Bip32)
                        {
                            keyData = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                        }
                        else if (type == CfdDescriptorKeyType.Bip32Priv)
                        {
                            keyData = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                        }
                        else if (type == CfdDescriptorKeyType.SchnorrPubkey)
                        {
                            keyData = new CfdKeyData(new SchnorrPubkey(tempPubkey));
                        }
                        else
                        {
                            keyData = new CfdKeyData(new Pubkey(tempPubkey));
                        }
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, (CfdHashType)hashType, new Address(tempAddress), keyData);
                        break;

                    case CfdDescriptorScriptType.Sh:
                    case CfdDescriptorScriptType.Wsh:
                    case CfdDescriptorScriptType.Multi:
                    case CfdDescriptorScriptType.SortedMulti:
                        if (isMultisig)
                        {
                            CfdKeyData[] keyList = new CfdKeyData[maxKeyNum];
                            for (uint multisigIndex = 0; multisigIndex < maxKeyNum; ++multisigIndex)
                            {
                                IntPtr multisigPubkey     = IntPtr.Zero;
                                IntPtr multisigExtPubkey  = IntPtr.Zero;
                                IntPtr multisigExtPrivkey = IntPtr.Zero;
                                ret = NativeMethods.CfdGetDescriptorMultisigKey(handle.GetHandle(), descriptorHandle,
                                                                                multisigIndex, out int multisigKeyType, out multisigPubkey,
                                                                                out multisigExtPubkey, out multisigExtPrivkey);
                                if (ret != CfdErrorCode.Success)
                                {
                                    handle.ThrowError(ret);
                                }
                                tempPubkey     = CCommon.ConvertToString(multisigPubkey);
                                tempExtPubkey  = CCommon.ConvertToString(multisigExtPubkey);
                                tempExtPrivkey = CCommon.ConvertToString(multisigExtPrivkey);
                                type           = (CfdDescriptorKeyType)multisigKeyType;
                                if (type == CfdDescriptorKeyType.Bip32)
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new ExtPubkey(tempExtPubkey));
                                }
                                else if (type == CfdDescriptorKeyType.Bip32Priv)
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new ExtPrivkey(tempExtPrivkey));
                                }
                                else
                                {
                                    keyList[multisigIndex] = new CfdKeyData(new Pubkey(tempPubkey));
                                }
                            }
                            data = new CfdDescriptorScriptData(
                                (CfdDescriptorScriptType)scriptType,
                                depth, (CfdHashType)hashType, new Address(tempAddress),
                                new Script(tempRedeemScript), keyList, requireNum);
                            rootData = new CfdDescriptorScriptData(rootData.ScriptType, 0,
                                                                   rootData.HashType, rootData.Address, rootData.RedeemScript,
                                                                   rootData.KeyData, keyList, requireNum);
                        }
                        else
                        {
                            data = new CfdDescriptorScriptData(
                                (CfdDescriptorScriptType)scriptType,
                                depth, (CfdHashType)hashType, new Address(tempAddress),
                                new Script(tempRedeemScript));
                        }
                        break;

                    case CfdDescriptorScriptType.Raw:
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, new Script(tempRedeemScript));
                        break;

                    case CfdDescriptorScriptType.Addr:
                        data = new CfdDescriptorScriptData(
                            (CfdDescriptorScriptType)scriptType,
                            depth, (CfdHashType)hashType, new Address(tempAddress));
                        break;

                    default:
                        data = new CfdDescriptorScriptData();
                        break;
                    }
                    list[index] = data;

                    if (scriptType == (int)CfdDescriptorScriptType.Combo)
                    {
                        // TODO: combo data is top only.
                        CfdDescriptorScriptData[] newList = { list[0] };
                        list = newList;
                        break;
                    }
                }
                return(list);
            }
            finally
            {
                NativeMethods.CfdFreeDescriptorHandle(
                    handle.GetHandle(), descriptorHandle);
            }
        }
예제 #4
0
        private static CfdDescriptorScriptData AnalyzeScriptList(CfdDescriptorScriptData[] scriptList)
        {
            if ((scriptList[0].HashType == CfdHashType.P2wsh) ||
                (scriptList[0].HashType == CfdHashType.P2sh))
            {
                if ((scriptList.Length > 1) && (scriptList[1].HashType == CfdHashType.P2pkh))
                {
                    CfdDescriptorScriptData data = new CfdDescriptorScriptData(
                        scriptList[0].ScriptType,
                        scriptList[0].Depth,
                        scriptList[0].HashType,
                        scriptList[0].Address,
                        scriptList[0].RedeemScript,
                        scriptList[1].KeyData, Array.Empty <CfdKeyData>(), 0);
                    return(data);
                }
            }
            if (scriptList[0].HashType == CfdHashType.P2shP2wsh)
            {
                if ((scriptList.Length > 2) && (scriptList[2].HashType == CfdHashType.P2pkh))
                {
                    CfdDescriptorScriptData data = new CfdDescriptorScriptData(
                        scriptList[0].ScriptType, scriptList[0].Depth,
                        scriptList[0].HashType, scriptList[0].Address,
                        scriptList[1].RedeemScript,
                        scriptList[2].KeyData, Array.Empty <CfdKeyData>(), 0);
                    return(data);
                }
            }
            if (scriptList.Length == 1)
            {
                return(scriptList[0]);
            }

            if (scriptList[0].HashType == CfdHashType.P2shP2wsh)
            {
                if (scriptList[1].MultisigRequireNum > 0)
                {
                    CfdDescriptorScriptData data = new CfdDescriptorScriptData(
                        scriptList[0].ScriptType,
                        scriptList[0].Depth,
                        scriptList[0].HashType,
                        scriptList[0].Address,
                        scriptList[1].RedeemScript,
                        scriptList[1].MultisigKeyList.ToArray(),
                        scriptList[1].MultisigRequireNum);
                    return(data);
                }
                else
                {
                    CfdDescriptorScriptData data = new CfdDescriptorScriptData(
                        scriptList[0].ScriptType,
                        scriptList[0].Depth,
                        scriptList[0].HashType,
                        scriptList[0].Address,
                        scriptList[1].RedeemScript);
                    return(data);
                }
            }
            else if (scriptList[0].HashType == CfdHashType.P2shP2wpkh)
            {
                CfdDescriptorScriptData data = new CfdDescriptorScriptData(
                    scriptList[0].ScriptType,
                    scriptList[0].Depth,
                    scriptList[0].HashType,
                    scriptList[0].Address,
                    scriptList[1].KeyData);
                return(data);
            }
            return(scriptList[0]);
        }