From what I understand, a non-SegWit P2PH address is obtained by hashing the redeem script
ScriptPubKey
I had the same problem and I have resolved it with this C++ code, and I think this code is self-describing.
If you have the ScriptPubKey extract from the blk file, this is code calculate the correct address P2SH.
string opcode = hex.substr(0, 2);
int32_t optValue = std::stoul(opcode, nullptr, 16);
auto optMap = bitcoinOpCode.opCodeList.find(optValue);
string optCode = optMap->second;
if (optCode == "OP_HASH160") {
cout << "Finded the P2SH";
string scriptHash = hex.substr(4, hex.length() - 6);
Bytes bytes = hexBytes(scriptHash.c_str());
bytes.insert(bytes.begin(), 1, 5);
string address = EncodeBase58Check(bytes);
cout << "P2SH addresss is " << address;
string endOpCode = hex.substr(hex.length() - 2, 2);
int32_t optValueEnd = std::stoul(endOpCode, nullptr, 16);
auto optMapEnd = bitcoinOpCode.opCodeList.find(optValueEnd);
string optCodeEnd = optMapEnd->second;
if(optCodeEnd == "OP_EQUAL"){
cout << "\n\t----------------------------------------| Results |-----------------------------------" << endl;
cout << "\t ### Script PUB KEY HASH ### " << endl;
cout << "\t" << optCode << " " << scriptHash << " " << optCodeEnd << endl;
cout << "\t " << endl;
cout << "\t The public key: " << address << " " << endl;
cout << endl;
cout << "\t https://blockstream.info/address/" << address << endl;
cout << "\t______________________________________________________________________________________"<< endl;
}
}
how I do calculate the correct address?
You know the complete P2SH, an example this
OP_0 <A Signature> <B Signature> OP_2 <Public key A> <Public key B>
<Public key C> OP_3 OP_CHECKMULTISIG
OP_HASH160 <ScriptSig Hash> OP_EQUAL
Inside the this code you can find the scriptSig, so this:
OP_0 <A Signature> <B Signature> OP_2 <Public key A> <Public key B>
<Public key C> OP_3 OP_CHECKMULTISIG
and the ScriptPubKey, so this:
OP_HASH160 <ScriptSig Hash> OP_EQUAL
With my code, I work only with the scriptPubKey and I found the dimension with the following mode
OP_HASH160 = hex.substr(0, 2);
<ScriptSig Hash> = hex.substr(4, hex.length() - 6);
OP_EQUAL = hex.substr(hex.length() - 2, 2);
on the data hex <ScriptSig Hash> I can run the EncodeBase58Check encoding, I have to change the code of bitcoin core(this) for change the hash library.
Inside the bitcoin core code you can find the correct execution of EncodeBase58 (here)
Another important code is this to insert the mainet flag inside the byte.
bytes.insert(bytes.begin(), 1, 5);
ScriptSig
The scriptSig inside is composed to two component, so:
I didn't have to try to decode with code the script sig but I think this is more difficult to others because the dimension is not standard because the program control is a script P2MS and this script has more combination.
I can suggest you create a decompiler intelligent for scriptSig because if you get the OP_2 hex inside the script you can read 2 signature but it is possible to get the OP_14 and your parser must be read 14 signature.
I can suggest you to start decompiler the ScriptSig to end because you know the dimension end hexadecimal.
When you have extracted the pubkey and if you want an address bitcoin you can read my question here
Thanks a lot for the detailed algorithm explanation, but my question was more about the standard ScriptSig follows, creating a loop that extracts the redeem script is not hard, yet I must be sure the format is always of the form:
<OP_0><{data1 size}{data1}><{data2 size}{data2}>...<OP_1><OP-PUSHDATA1><redeemScript> – iMil – 2019-11-21T11:15:16.233
1@iMil No because the signature depends on the combination of P2MS script, I have mentioned this argument in the ScriptSig section. – vincenzopalazzo – 2019-11-21T14:04:47.793