Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BlockSci v0.6 not recognizing ZCash t-addr addresses #246

Closed
jredondo opened this issue Feb 4, 2019 · 3 comments
Closed

BlockSci v0.6 not recognizing ZCash t-addr addresses #246

jredondo opened this issue Feb 4, 2019 · 3 comments
Labels

Comments

@jredondo
Copy link

jredondo commented Feb 4, 2019

Greetings.
I'm using BlockSci AMI with BlockSci v0.6 (commit 304e1ff7eb670e5fff161688e26e698c56f21e28).
It seems I have parsed successfully the ZCash blockchain since parser finished with the expected message and the data directory seems filled as expected.
Nonetheless, it seems BlockSci is not able to interpret ZCash t-addr addresses.
I have this small code for testing:

#include <blocksci/blocksci.hpp>
#include <blocksci/chain/algorithms.hpp>
#include <blocksci/chain/transaction.hpp>
#include <blocksci/chain/block.hpp>
#include <blocksci/chain/blockchain.hpp>
#include <blocksci/script.hpp>
#include <blocksci/address/address.hpp>
#include <blocksci/chain/transaction_range.hpp>

#include <range/v3/all.hpp>

#include <numeric>
#include <chrono>
#include <unordered_map>
#include <map>
#include <fstream>
#include <iostream>
#include <set>
#include <functional>
#include <string>

using namespace blocksci;

int main(int argc, const char * argv[]) {
    Blockchain chain(argv[1]);
    auto begin = std::chrono::steady_clock::now();

    auto address = getAddressFromString(argv[2], chain.getAccess());
    if(address == ranges::nullopt) {
        std::cout << "Null address: " << argv[2]  << std::endl ;
        return -1;
    }

    std::cout << "Address: " << (*address).toString() << std::endl ;

    //std::cout << "Address: " << address->toString() << std::endl ;
    std::cout << "Address balance: " << (*address).calculateBalance(std::atoi(argv[3])) << std::endl ;

    auto endTime = std::chrono::steady_clock::now();
    double timeMSecs = std::chrono::duration_cast<std::chrono::microseconds>(endTime - begin).count();
    std::cout << "time: " << timeMSecs << std::endl ;
}

After running it like this (ZCash):

user@server:...$ ./test_balance ../../blocksci-http-server/conf/conf_zch.txt t1aZvxRLCGVeMPFXvqfnBgHVEbi4c6g8MVa 1000000
Null address: t1aZvxRLCGVeMPFXvqfnBgHVEbi4c6g8MVa
user@server:...$ 

And after running like (Litecoin):

user@server:...$ ./test_balance ../../blocksci-http-server/conf/conf_ltc.txt ltc1qxhpwa9u8dwtpegj8gkay4ewju7py09uawhp28p 10000000
Address: WitnessPubkeyAddress(ltc1qxhpwa9u8dwtpegj8gkay4ewju7py09uawhp28p)
Address balance: 1017909332001
time: 17651
user@server:...$ 

Here are the config files used up there:
ZCash:

{
    "chainConfig": {
        "coinName": "zcash",
        "dataDirectory": "/home/ubuntu/zcash",
        "pubkeyPrefix": [
            28,
            184
        ],
        "scriptPrefix": [
            28,
            189
        ],
        "segwitActivationHeight": 2147483647,
        "segwitPrefix": "NONE"
    },
    "parser": {
        "maxBlockNum": -6,
        "rpc": {
            "address": "127.0.0.1",
            "password": "test",
            "port": 8232,
            "username": "test"
        }
    },
    "version": 5
}

Litecoin:

{
    "chainConfig": {
        "coinName": "litecoin",
        "dataDirectory": "/home/ubuntu/litecoin",
        "pubkeyPrefix": [
            48
        ],
        "scriptPrefix": [
            50
        ],
        "segwitActivationHeight": 1201536,
        "segwitPrefix": "ltc"
    },
    "parser": {
        "disk": {
            "blockMagic": 3686187259,
            "coinDirectory": "/home/ubuntu/.litecoin",
            "hashFuncName": "doubleSha256"
        },
        "maxBlockNum": -6
    },
    "version": 5
}

Please let me know if there is anything else I could provide.
Thanks in advance.

@jredondo jredondo changed the title BlockSci v0.6 not parsing ZCash t-addr addresses BlockSci v0.6 not recognizing ZCash t-addr addresses Feb 4, 2019
@jredondo
Copy link
Author

jredondo commented Feb 4, 2019

Using gdb I have realized that at this point the variable type is blocksci::AddressType::NONSTANDARD and thus addressNum never gets anything different than ranges::nullopt.

@jredondo
Copy link
Author

jredondo commented Feb 5, 2019

I have implemented this small patch and it seems to work as expected using:

auto address = getAddressFromString_2(argv[2], chain.getAccess());

This is the git diff with commit 6a07f305834c197c1c641eae32bf23da2b31adb3:

user@server:~/jredondo/BlockSci$ git diff
diff --git a/include/blocksci/address/address.hpp b/include/blocksci/address/address.hpp
index af1e6f5..c16e4e2 100644
--- a/include/blocksci/address/address.hpp
+++ b/include/blocksci/address/address.hpp
@@ -110,6 +110,7 @@ namespace blocksci {
     void BLOCKSCI_EXPORT visit(const Address &address, const std::function<bool(const Address &)> &visitFunc);
     
     ranges::optional<Address> BLOCKSCI_EXPORT getAddressFromString(const std::string &addressString, DataAccess &access);
+    ranges::optional<Address> BLOCKSCI_EXPORT getAddressFromString_2(const std::string &addressString, DataAccess &access);
     
     std::vector<Address> BLOCKSCI_EXPORT getAddressesWithPrefix(const std::string &prefix, DataAccess &access);
     
diff --git a/src/address/address.cpp b/src/address/address.cpp
index ebe0b0e..1c663f9 100644
--- a/src/address/address.cpp
+++ b/src/address/address.cpp
@@ -232,6 +232,45 @@ namespace blocksci {
     ScriptBase Address::getBaseScript() const {
         return ScriptBase(*this);
     }
+
+    ranges::optional<Address> getAddressFromString_2(const std::string &addressString, DataAccess &access) {
+        if (addressString.compare(0, access.config.chainConfig.segwitPrefix.size(), access.config.chainConfig.segwitPrefix) == 0) {
+            std::pair<int, std::vector<uint8_t> > decoded = segwit_addr::decode(access.config.chainConfig.segwitPrefix, addressString);
+            if (decoded.first == 0) {
+                if (decoded.second.size() == 20) {
+                    uint160 pubkeyHash(decoded.second.begin(), decoded.second.end());
+                    ranges::optional<uint32_t> addressNum = access.getHashIndex().getPubkeyHashIndex(pubkeyHash);
+                    if (addressNum) {
+                        return Address{*addressNum, AddressType::WITNESS_PUBKEYHASH, access};
+                    }
+                } else if (decoded.second.size() == 32) {
+                    uint256 scriptHash(decoded.second.begin(), decoded.second.end());
+                    ranges::optional<uint32_t> addressNum = access.getHashIndex().getScriptHashIndex(scriptHash);
+                    if (addressNum) {
+                        return Address{*addressNum, AddressType::WITNESS_SCRIPTHASH, access};
+                    }
+                }
+            }
+            return ranges::nullopt;
+        }
+
+        CBitcoinAddress address;
+        assert(access.config.chainConfig.segwitPrefix.size() ==access.config.chainConfig.pubkeyPrefix.size())
+        address.SetString(addressString.c_str(), access.config.chainConfig.pubkeyPrefix.size());
+        uint160 hash;
+        blocksci::AddressType::Enum type;
+        std::tie(hash, type) = address.Get(access.config.chainConfig);
+        ranges::optional<uint32_t> addressNum = ranges::nullopt;
+        if (type == AddressType::Enum::PUBKEYHASH) {
+            addressNum = access.getHashIndex().getPubkeyHashIndex(hash);
+        } else if (type == AddressType::Enum::SCRIPTHASH) {
+            addressNum = access.getHashIndex().getScriptHashIndex(hash);
+        }
+        if (addressNum) {
+            return Address{*addressNum, type, access};
+        } else {
+            return ranges::nullopt;
+        }
+    }
     
     ranges::optional<Address> getAddressFromString(const std::string &addressString, DataAccess &access) {
         if (addressString.compare(0, access.config.chainConfig.segwitPrefix.size(), access.config.chainConfig.segwitPrefix) == 0) {
diff --git a/src/scripts/bitcoin_base58.cpp b/src/scripts/bitcoin_base58.cpp
index 66f4e9d..707e5a1 100755
--- a/src/scripts/bitcoin_base58.cpp
+++ b/src/scripts/bitcoin_base58.cpp
@@ -206,6 +206,12 @@ namespace blocksci {
         return 0;
     }
 
+    CBitcoinAddress::CBitcoinAddress()
+    {
+        vchVersion.clear();
+        vchData.clear();
+    }
+
 
     CBitcoinAddress::CBitcoinAddress(const uint160 &dest, AddressType::Enum type, const ChainConfiguration &config) {
         if (type == AddressType::Enum::PUBKEYHASH || type == AddressType::Enum::PUBKEY || type == AddressType::Enum::MULTISIG_PUBKEY) {
diff --git a/src/scripts/bitcoin_base58.hpp b/src/scripts/bitcoin_base58.hpp
index 41c7c55..4e5144c 100755
--- a/src/scripts/bitcoin_base58.hpp
+++ b/src/scripts/bitcoin_base58.hpp
@@ -104,6 +104,7 @@ namespace blocksci {
      */
     class CBitcoinAddress : public CBase58Data {
     public:
+        CBitcoinAddress();
         CBitcoinAddress(const uint160 &dest, AddressType::Enum type, const ChainConfiguration &config);
         CBitcoinAddress(const uint160 &dest, const std::vector<unsigned char>& version);
         CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
user@server:~/jredondo/BlockSci$ 

maltemoeser added a commit to maltemoeser/BlockSci that referenced this issue May 1, 2019
Previously a default of 1 was used for nVersionBytes, resulting in addresses not being found when nVersionBytes was > 1 (e.g., for Zcash). Implementation assumes pubkeyPrefix and scriptPrefix have the same length.

Fixes: citp#246
maltemoeser added a commit that referenced this issue May 7, 2019
Previously a default of 1 was used for nVersionBytes, resulting in addresses not being found when nVersionBytes was > 1 (e.g., for Zcash). Implementation assumes pubkeyPrefix and scriptPrefix have the same length.

Fixes: #246
@jredondo
Copy link
Author

Thanks for fixing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants