Using zCash through BitcoinJ

0 votes

Using zCash with BitcoinJ seems a reasonable advance for me since I need to monitor various currencies for an academic project. Currently, I run a full node with zCash along with BitcoinJ for Bitcoin and Litecoin using network params from the Dogecoin developers.

Out of the circumstance that zCash uses a lot of Bitcoin's Codebase, I think this might be compatible, but unfortunately, I'm unable to get it to work alone.

Here's my approach to ZcashMainNetParams:-

public class ZcashMainNetParams extends AbstractZcashMainNetParams { public static final int MAINNET_MAJORITY_WINDOW = 1000; public static final int MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED = 950; public static final int MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = 750; public ZcashMainNetParams() { super(); interval = INTERVAL; targetTimespan = TARGET_TIMESPAN; maxTarget = Utils.decodeCompactBits(0x1d00ffffL); dumpedPrivateKeyHeader = 128; addressHeader = 0; p2shHeader = 5; acceptableAddressCodes = new int[] { addressHeader, p2shHeader }; port = 8233; packetMagic = 0xf9beb4d9 /* netmagic same as BTC ??? */; bip32HeaderPub = 0x0488B21E; //The 4 byte header that serializes in base58 to "xpub". bip32HeaderPriv = 0x0488ADE4; //The 4 byte header that serializes in base58 to "xprv" majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE; majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED; majorityWindow = MAINNET_MAJORITY_WINDOW; genesisBlock = createGenesis(this); id = ID_MAINNET; subsidyDecreaseBlockCount = 210000; spendableCoinbaseDepth = 100; String genesisHash = genesisBlock.getHashAsString(); checkState(genesisHash.equals("00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08"), genesisHash); /* updated */ // 

This contains (at a minimum) the blocks which are not BIP30 compliant. BIP30 changed how duplicate // transactions are handled. Duplicated transactions could occur in the case where a coinbase had the same // extraNonce and the same outputs but appeared at different heights and greatly complicated re-org handling. // Having these here simplifies block connection logic considerably. checkpoints.put(2500,

Sha256Hash.wrap("00000006dc968f600be11a86cbfbf7feb61c7577f45caced2e82b6d261d19744")) /* updated */; checkpoints.put(15000, Sha256Hash.wrap("00000000b6bc56656812a5b8dcad69d6ad4446dec23b5ec456c18641fb5381ba")) /* updated */; checkpoints.put(67500, Sha256Hash.wrap("000000006b366d2c1649a6ebb4787ac2b39c422f451880bc922e3a6fbd723616")) /* updated */; dnsSeeds = new String[] { "dnsseed.z.cash", // Zcash "dnsseed.str4d.xyz", // @str4d "dnsseed.znodes.org" // @bitcartel }; } private static AltcoinBlock createGenesis(NetworkParameters params) { AltcoinBlock genesisBlock = new AltcoinBlock(params, 4L); Transaction t = new Transaction(params); try { byte[] bytes = Hex.decode ("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"); t.addInput(new TransactionInput(params, t, bytes)); ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream(); Script.writeBytes(scriptPubKeyBytes, Hex.decode ("000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce157")); scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG); t.addOutput(new TransactionOutput(params, t, COIN.multiply(50), scriptPubKeyBytes.toByteArray())); } catch (Exception e) { // Cannot happen. throw new RuntimeException(e); } genesisBlock.addTransaction(t); genesisBlock.setTime(1477641360L); genesisBlock.setDifficultyTarget(504365040L); genesisBlock.setNonce(0x0000000000000000000000000000000000000000000000000000000000001257L); return genesisBlock; } private static ZcashMainNetParams instance; public static synchronized ZcashMainNetParams get() { if (instance == null) { instance = new ZcashMainNetParams(); } return instance; } @Override public String getPaymentProtocolId() { return PAYMENT_PROTOCOL_ID_MAINNET; } }


The abstract class is also re-used from the dogecoin developers:

public abstract class AbstractZcashMainNetParams extends NetworkParameters { /** * Scheme part for Bitcoin URIs. */ public static final String BITCOIN_SCHEME = "zcash"; public static final int REWARD_HALVING_INTERVAL = 210000; private static final Logger log = LoggerFactory.getLogger(AbstractZcashMainNetParams.class); public AbstractZcashMainNetParams() { super(); } /** * Checks if we are at a reward halving point. * @param height The height of the previous stored block * @return If this is a reward halving point */ public final boolean isRewardHalvingPoint(final int height) { return ((height + 1) % REWARD_HALVING_INTERVAL) == 0; } /** * Checks if we are at a difficulty transition point. * @param height The height of the previous stored block * @return If this is a difficulty transition point */ public final boolean isDifficultyTransitionPoint(final int height) { return ((height + 1) % this.getInterval()) == 0; } @Override public void checkDifficultyTransitions(final StoredBlock storedPrev, final Block nextBlock, final BlockStore blockStore) throws VerificationException, BlockStoreException { final Block prev = storedPrev.getHeader(); // Is this supposed to be a difficulty transition point? if (!isDifficultyTransitionPoint(storedPrev.getHeight())) { // No ... so check the difficulty didn't actually change. if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget()) throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() + ": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " + Long.toHexString(prev.getDifficultyTarget())); return; } // We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every // two weeks after the initial block chain download. final Stopwatch watch = Stopwatch.createStarted(); Sha256Hash hash = prev.getHash(); StoredBlock cursor = null; final int interval = this.getInterval(); for (int i = 0; i < interval; i++) { cursor = blockStore.get(hash); if (cursor == null) { // This should never happen. If it does, it means we are following an incorrect or busted chain. throw new VerificationException( "Difficulty transition point but we did not find a way back to the last transition point. Not found: " + hash); } hash = cursor.getHeader().getPrevBlockHash(); } checkState(cursor != null && isDifficultyTransitionPoint(cursor.getHeight() - 1), "Didn't arrive at a transition point."); watch.stop(); if (watch.elapsed(TimeUnit.MILLISECONDS) > 50) log.info("Difficulty transition traversal took {}", watch); Block blockIntervalAgo = cursor.getHeader(); int timespan = (int) (prev.getTimeSeconds() - blockIntervalAgo.getTimeSeconds()); // Limit the adjustment step. final int targetTimespan = this.getTargetTimespan(); if (timespan < targetTimespan / 4) timespan = targetTimespan / 4; if (timespan > targetTimespan * 4) timespan = targetTimespan * 4; BigInteger newTarget = Utils.decodeCompactBits(prev.getDifficultyTarget()); newTarget = newTarget.multiply(BigInteger.valueOf(timespan)); newTarget = newTarget.divide(BigInteger.valueOf(targetTimespan)); if (newTarget.compareTo(this.getMaxTarget()) > 0) { log.info("Difficulty hit proof of work limit: {}", newTarget.toString(16)); newTarget = this.getMaxTarget(); } int accuracyBytes = (int) (nextBlock.getDifficultyTarget() >>> 24) - 3; long receivedTargetCompact = nextBlock.getDifficultyTarget(); // The calculated difficulty is to a higher precision than received, so reduce here. BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8); newTarget = newTarget.and(mask); long newTargetCompact = Utils.encodeCompactBits(newTarget); if (newTargetCompact != receivedTargetCompact) throw new VerificationException("Network provided difficulty bits do not match what was calculated: " + Long.toHexString(newTargetCompact) + " vs " + Long.toHexString(receivedTargetCompact)); } @Override public Coin getMaxMoney() { return MAX_MONEY; } @Override public Coin getMinNonDustOutput() { return Transaction.MIN_NONDUST_OUTPUT; } @Override public MonetaryFormat getMonetaryFormat() { return new MonetaryFormat(); } @Override public int getProtocolVersionNum(final ProtocolVersion version) { return version.getBitcoinProtocolVersion(); } @Override public BitcoinSerializer getSerializer(boolean parseRetain) { return new BitcoinSerializer(this, parseRetain); } @Override public String getUriScheme() { return BITCOIN_SCHEME; } @Override public boolean hasMaxMoney() { return true; } }


My Problem here is basically the generation of the genesis block. I'm unable to forge it with the right hash. I believe it has to do with the transaction I try to understand in the chainparams.cpp of zCash. However my genesis block has the hash of e88b11fd3581e170f86db9c574f65c0ada3216e126011ac968869f1b64ea4c4a instead of the required 00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08

Thanks for any kind of help, even including a reasonable conclusion that this is not possible.

Apr 6 in Blockchain by Soham
• 8,730 points
39 views

1 answer to this question.

0 votes

Your code isn't accounting for the format of the Zcash block header, which is different to both Bitcoin and most altcoins. You need to add the hashReserved and nSolution fields, and make nNonce 256 bits instead of 32.

answered Apr 12 by Rahul
• 8,980 points

Related Questions In Blockchain

0 votes
1 answer

Generate Ethereum addresses in HD Wallet using public key only (bitcoinj/web3j)

Like Bitcoin, Ethereum uses secp256k1. Ethereum addresses ...READ MORE

answered Apr 12 in Blockchain by Soham
• 8,730 points
311 views
+1 vote
3 answers

Is it possible to store data about arbitrary objects on the blockchain using smart contracts?

Consider following tutorial from Hyperledger Fabric "Getting Started" pages. Basically ...READ MORE

answered Aug 30, 2018 in Blockchain by Artem
495 views
+3 votes
2 answers

How to run ethereumjs using Node.JS

You need to install testrpc globally on ...READ MORE

answered Mar 27, 2018 in Blockchain by ned_crew
• 1,610 points
576 views
+1 vote
1 answer

Transaction using Blockchain wallet APi

Each transaction requires a fee to be ...READ MORE

answered Jun 19, 2018 in Blockchain by Perry
• 17,100 points
272 views
0 votes
1 answer

Protocols used in a distributed/dlt system for the nodes to establish communication

yes all are over TCP/IP connections secured by TLS encryption in hashgraph architecture-hashgraph, ...READ MORE

answered Aug 6, 2018 in Blockchain by aryya
• 7,440 points
622 views
0 votes
1 answer

Truffle tests not running after truffle init

This was a bug. They've fixed it. ...READ MORE

answered Sep 11, 2018 in Blockchain by Christine
• 15,790 points
960 views
0 votes
1 answer
0 votes
1 answer

Currency Conversion using PHP

 An example of converting EUR to USD ...READ MORE

answered Mar 24 in Blockchain by Rahul
• 8,980 points
26 views
0 votes
1 answer

How to set fee in raw bitcoin transaction using btcutil

To answer your question, the settxfee is ...READ MORE

answered Mar 24 in Blockchain by Rahul
• 8,980 points
52 views
webinar REGISTER FOR FREE WEBINAR X
Send OTP
REGISTER NOW
webinar_success Thank you for registering Join Edureka Meetup community for 100+ Free Webinars each month JOIN MEETUP GROUP