Author

Topic: ScriptHash to CKeyID (Read 203 times)

legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
February 10, 2022, 01:28:30 PM
#9
Little context, currently I'm updating Devcoin from old Bitcoin 0.8.x up to Bitcoin Core 22.x, so many things have changed!

Interesting. How did you manage to migrate the C++98(??) codebase all the way to the present C++17 codebase?

I have attempted to retrofit parts of Bitcoin Core to other programs but spent many days downgrading them to C++11 equivalents, such is how deeply engrained they are that the only feasible way to do it would be to fit your existing modifications on to the Core codebase instead of the other way around (I believe this is why many forks are stuck on old versions of Core perpetually).
sr. member
Activity: 470
Merit: 350
February 10, 2022, 12:25:32 AM
#8
For those looking to get CKeyID, you might be going the wrong path (like I did). I needed to convert an address in String format into a hash that can make into a custom transaction, which is something that Devcoin does in order to transfer a certain amount of newly minted coins to a list of addresses (beneficiaries).

Little context, currently I'm updating Devcoin from old Bitcoin 0.8.x up to Bitcoin Core 22.x, so many things have changed! Also, I was missing the fact that Bitcoin transactions need pubkey hashes, not the actual pubkeys. An address derives from a pubkey hash, which then derives from a pub key. Btw, there is no way back from hashes to pub keys, since that would break the actual purpose of hashes (they are irreversible). Hopefully, address are base58 formatted, it means that they are reversible to their hash. Last but not least, modern Bitcoin has great functions that handle the different types of addresses and their hashes, so we do the following:

Code:
CMutableTransaction myTx;
myTx.vin.resize(1);
myTx.vin[0].prevout.SetNull();

const string addressString = "my_address";
CAmount amount = 10;
string error_str;
CTxDestination destination = DecodeDestination(addressString, error_str);

// You don't need much more checks than the following
if (!IsValidDestination(destination)) {
   return error(error_str);
}

CScript pubKeyHash = GetScriptForDestination(destination);
myTx.vout[0] = CTxOut(amount, pubKeyHash);

An implementation of the above: https://github.com/devcoin/core/blob/4ec355c0e42108afcfc8d2467fdeed0119a4123b/src/miner.cpp#L163

- develCuy
newbie
Activity: 29
Merit: 6
May 25, 2021, 02:42:03 AM
#7
@NotATether I missed your comment yesterday, thank you for your help, it solved my problem.
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
May 24, 2021, 11:09:07 AM
#6
According to DecodeBase58Check signature it's returns bool and not hash160:

Code:
bool DecodeBase58Check(const std::string& str, std::vector& vchRet, int max_ret)

Did you meant to vchRet?

Yes that's what I meant, I had already read the Doxygen classes on doxygen.bitcoincore.org.

So what you can do is reuse code from your DecodeAddressDestination to generate the CKeyID that is made from the base58-to-uint160 process like so:

Code:
        string sKey = "my_address";
        std::vector prefix = std::vector(1,5);
        std::vector data;
        uint160 hash;
        if (DecodeBase58Check(sKey, data, 256)) {
               // For your example the checks can be skipped since you have already
               // verified it returns a ScriptHash()
               std::copy(data.begin() + prefix.size(), data.end(), hash.begin());
               CKeyID key = CKeyID(hash);
        }
newbie
Activity: 29
Merit: 6
May 24, 2021, 10:01:54 AM
#5
According to DecodeBase58Check signature it's returns bool and not hash160:

Code:
bool DecodeBase58Check(const std::string& str, std::vector& vchRet, int max_ret)

Did you meant to vchRet?
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
May 24, 2021, 09:57:20 AM
#4
There is a uint160 returned by DecodeBase58Check, why aren't you using that?

Only ScriptHash can extract the uint160 using begin() and end() iterators inherited from its superclass. When you turn it into a CTxDestination you lose the bytes because it's converted into a vector of opcodes which hashes into something different.
newbie
Activity: 29
Merit: 6
May 24, 2021, 09:18:33 AM
#3
The address is P2SH.
DecodeAddressDestination is a function that I added to base58.cpp. I added the implementation.

Code:
CTxDestination DecodeAddressDestination(const std::string& str, const std::vector& pubkey_prefix) {
        std::vector data;
        uint160 hash;
        if (DecodeBase58Check(str, data, 256)) {

        // base58-encoded Bitcoin addresses.
        // Public-key-hash-addresses have version 0 (or 111 testnet).
        // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
        if (data.size() == hash.size() + pubkey_prefix.size() &&
        std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
            std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
            return ScriptHash(hash);
            }
        }
        return CNoDestination();
}
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
May 24, 2021, 09:02:51 AM
#2
Is it a P2SH or P2[W]PKH address?

Where does ::DecodeAddressDestination come from? It is not an API function and the double colons indicate it's in the same class as your problematic code.

CKeyID expects to be initialized with a uint160 but as far as I can see, CScript does not have a hashing method to return one.
newbie
Activity: 29
Merit: 6
May 24, 2021, 04:47:34 AM
#1
I have a valid base58 address that I got using getnewaddress command.
I'm trying to convert it to CKeyID object but I have some difficulties.

The problematic code:

Code:
string sKey = "my_address"; // it's not the real address
std::vector prefix = std::vector(1,5);
CTxDestination dest = ::DecodeAddressDestination(sKey, prefix);
CScript script = GetScriptForDestination(dest);
CKeyID key = CKeyID(script);

I also tried this way:
Code:
CKeyID key;
key.SetHex(sKey);

The second way printed me this value, which is incorrect: 000000000000000000000000000000000000000b

At the debugging I can see that dest value is ScriptHash
What I'm doing wrong?
Jump to: