Bit-Wasp / bitcoin-php

Bitcoin implementation in PHP
The Unlicense
1.05k stars 418 forks source link

Dash Address problem (testnet) #766

Closed tulang3587 closed 5 years ago

tulang3587 commented 5 years ago

When generating a Dash address, mainnet returns a valid address. But it's always invalid for testnet.

I've tried using both v0.0.35.1 and v1.0.0:

The resulting address is always invalid for NetworkFactory::dashTestnet(), but NetworkFactory::dash() is fine. One of the generated address is: y26JSBDLEPbRD7iVWPz4Ck16uSKuqQ13Q8

I've tried searching the resulting testnet address on chain.so and importing them on my local Dash Core and it always fails:

$ dash-cli importaddress y26JSBDLEPbRD7iVWPz4Ck16uSKuqQ13Q8 testing false false
error code: -5
error message:
Invalid Dash address or script
afk11 commented 5 years ago

Hi, thanks for the question

I think if you check chainparams.cpp for the version of dash-testnet you're using, you'll see it's different (or decode the result of dash-cli getnewaddress and check it's bytes). Maybe they changed the version since we merged that, or we were wrong to begin with.

Simply extending DashTestnet in your project would be a really simple way of fixing it for you. Or there's a project @dan-da which provides up to date prefixes for multiple networks with a NetworkInterface implementation https://github.com/dan-da/coinparams-bitwasp-addon

I think my 'solution' to this long term is to delete implementations for other networks, and point devs to implementing NetworkInterface themselves, or to require a certain version of coinparams as a dependency. Every time we fix it in the library, we need to tag it as a new major version, since the change is for some users a BC break, and I'm getting pretty tired of doing that when the change doesn't affect logic, just a single data point in the lib

afk11 commented 5 years ago

I think I'll remove these objects from the main library, please feel free to copy them to your codebase and make whatever modifications are necessary. Or look into the project I linked above!

tulang3587 commented 5 years ago

Maybe they changed the version since we merged that

Exactly my thoughts.

And yeah, I've been thinking of making my own DashTestnet by extending the Network class to solve this, but I have no idea how to obtain the values for the network itself.

Is there any guide to do this? I've also looked at dan-da/coinparams, but even the 'magic' from your Dash implementation and dan-da's are completely different:

protected $p2pMagic = "bd6b0cbf";

and (from coinparams.json)

"magic": "0xbf0c6bbd"
afk11 commented 5 years ago

yea it should match whatevers in this file: https://github.com/dashpay/dash/blob/master/src/chainparams.cpp

tulang3587 commented 5 years ago

Can you give me some guidance for which values I need to find? I'm still not sure which values are needed for any custom network.

I'm trying to compare using Bitcoin network since it works fine. This is from the Bitcoin Network class:

protected $base58PrefixMap = [
    self::BASE58_ADDRESS_P2PKH => "00",
    self::BASE58_ADDRESS_P2SH => "05",
    self::BASE58_WIF => "80",
];

And from Bitcoin's chainparams:

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,128);
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};

I can't find the "00", "05" or "80" anywhere, and it's the same for the other variables as well. Searching for the p2p magic value even resulted in nothing.

afk11 commented 5 years ago

It's a difference in encoding. For addresses, chainparams.cpp uses decimal integers, whereas we use hex strings (0 = "00", 128 = "80")

And for extended pubkey stuff, they used hexadecimal notation for the numbers, so it's easy to compare against our hex strings.

tulang3587 commented 5 years ago

Thanks a lot for the information! I think I can probably make this work now.

I'll leave this as a handy note if anyone ever wanted to create their own custom network, and gets stuck like me. I haven't known where that pubkeyhash / p2pkh is from though.

protected $base58PrefixMap = [
    self::BASE58_ADDRESS_P2PKH => "00",
    self::BASE58_ADDRESS_P2SH => "05",
    self::BASE58_WIF => "80",
];

// bitcoin/src/chainparams.cpp
// convert to hex
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
protected $bech32PrefixMap = [
    self::BECH32_PREFIX_SEGWIT => "bc",
];

// bitcoin/src/chainparams.cpp
bech32_hrp = "bc";
protected $bip32PrefixMap = [
    self::BIP32_PREFIX_XPUB => "0488b21e",
    self::BIP32_PREFIX_XPRV => "0488ade4",
];

// bitcoin/src/chainparams.cpp
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
protected $bip32ScriptTypeMap = [
    self::BIP32_PREFIX_XPUB => ScriptType::P2PKH,
    self::BIP32_PREFIX_XPRV => ScriptType::P2PKH,
];

// ????
protected $signedMessagePrefix = "Bitcoin Signed Message";

// bitcoin/src/validation.cpp
const std::string strMessageMagic = "Bitcoin Signed Message:\n";
protected $p2pMagic = "d9b4bef9";

// bitcoin/src/chainparams.cpp
// reversed order
pchMessageStart[0] = 0xf9;
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;
tulang3587 commented 5 years ago

Almost forgot, this is my custom DashTestnet network class:

class DashTestnet extends Network
{
    /**
     * {@inheritdoc}
     * @see Network::$base58PrefixMap
     */
    protected $base58PrefixMap = [
        self::BASE58_ADDRESS_P2PKH => "8c",
        self::BASE58_ADDRESS_P2SH => "13",
        self::BASE58_WIF => "ef",
    ];

    /**
     * {@inheritdoc}
     * @see Network::$bip32PrefixMap
     */
    protected $bip32PrefixMap = [
        self::BIP32_PREFIX_XPUB => "043587cf",
        self::BIP32_PREFIX_XPRV => "04358394",
    ];

    /**
     * {@inheritdoc}
     * @see Network::$bip32ScriptTypeMap
     */
    protected $bip32ScriptTypeMap = [
        self::BIP32_PREFIX_XPUB => ScriptType::P2PKH,
        self::BIP32_PREFIX_XPRV => ScriptType::P2PKH,
    ];

    /**
     * {@inheritdoc}
     * @see Network::$signedMessagePrefix
     */
    protected $signedMessagePrefix = "DarkCoin Signed Message";

    /**
     * {@inheritdoc}
     * @see Network::$p2pMagic
     */
    protected $p2pMagic = "ffcae2ce";
}