AuxPoW extends ChildMessage { protected boolean checkProofOfWork(Sha256Hash hashAuxBlock, BigInteger target, boolean throwException) throws VerificationException { if (!(params instanceof AuxPoWNetworkParameters)) { if (throwException) { throw new VerificationException("Network parameters are not an instance of AuxPoWNetworkParameters, AuxPoW support is not available."); } return false; } final AuxPoWNetworkParameters altcoinParams = (AuxPoWNetworkParameters) params; if (0 != this.getCoinbaseBranch().getIndex()) { if (throwException) { throw new VerificationException("AuxPow is not a generate"); } return false; } if (!altcoinParams.isTestNet() && parentBlockHeader.getChainID() == altcoinParams.getChainID()) { if (throwException) { throw new VerificationException("Aux POW parent has our chain ID"); } return false; } if (this.getChainMerkleBranch().size() > 30) { if (throwException) { throw new VerificationException("Aux POW chain merkle branch too long"); } return false; } Sha256Hash nRootHash = getChainMerkleBranch().calculateMerkleRoot(hashAuxBlock); final byte[] vchRootHash = nRootHash.getBytes(); if (!getCoinbaseBranch().calculateMerkleRoot(getCoinbase().getHash()).equals(parentBlockHeader.getMerkleRoot())) { if (throwException) { throw new VerificationException("Aux POW merkle root incorrect"); } return false; } if (this.getCoinbase().getInputs().isEmpty()) { throw new VerificationException("Coinbase transaction has no inputs"); } final byte[] script = this.getCoinbase().getInput(0).getScriptBytes(); int pcHead = -1; int pc = -1; for (int scriptIdx = 0; scriptIdx < script.length; scriptIdx++) { if (arrayMatch(script, scriptIdx, MERGED_MINING_HEADER)) { if (pcHead >= 0) { if (throwException) { throw new VerificationException("Multiple merged mining headers in coinbase"); } return false; } pcHead = scriptIdx; } else if (arrayMatch(script, scriptIdx, vchRootHash)) { pc = scriptIdx; } } if (pc == -1) { if (throwException) { throw new VerificationException("Aux POW missing chain merkle root in parent coinbase"); } return false; } if (pcHead != -1) { if (pcHead + MERGED_MINING_HEADER.length != pc) { if (throwException) { throw new VerificationException("Merged mining header is not just before chain merkle root"); } return false; } } else { if (pc > MAX_INDEX_PC_BACKWARDS_COMPATIBILITY) { if (throwException) { throw new VerificationException("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase"); } return false; } } pc += vchRootHash.length; if ((script.length - pc) < 8) { if (throwException) { throw new VerificationException("Aux POW missing chain merkle tree size and nonce in parent coinbase"); } return false; } byte[] sizeBytes = Utils.reverseBytes(Arrays.copyOfRange(script, pc, pc + 4)); int branchSize = ByteBuffer.wrap(sizeBytes).getInt(); if (branchSize != (1 << getChainMerkleBranch().size())) { if (throwException) { throw new VerificationException("Aux POW merkle branch size does not match parent coinbase"); } return false; } long nonce = getNonceFromScript(script, pc); if (getChainMerkleBranch().getIndex() != getExpectedIndex(nonce, ((AuxPoWNetworkParameters) params).getChainID(), getChainMerkleBranch().size())) { if (throwException) { throw new VerificationException("Aux POW wrong index in chain merkle branch for chain ID " + ((AuxPoWNetworkParameters) params).getChainID() + ". Was " + getChainMerkleBranch().getIndex() + ", expected " + getExpectedIndex(nonce, ((AuxPoWNetworkParameters) params).getChainID(), getChainMerkleBranch().size())); } return false; } Sha256Hash hash = altcoinParams.getBlockDifficultyHash(getParentBlockHeader()); BigInteger hashVal = hash.toBigInteger(); if (hashVal.compareTo(target) > 0) { if (throwException) { throw new VerificationException("Hash is higher than target: " + hash.toString() + " vs " + target.toString(16)); } return false; } return true; } AuxPoW(NetworkParameters params, @Nullable Message parent);  AuxPoW(NetworkParameters params, byte[] payload, int offset, Message parent, MessageSerializer serializer);  AuxPoW(NetworkParameters params, byte[] payload, @Nullable Message parent, MessageSerializer serializer); int getOptimalEncodingMessageSize(); @Override String toString(); String toString(@Nullable AbstractBlockChain chain); @Override boolean equals(Object o); @Override int hashCode(); AltcoinBlock getParentBlockHeader(); Transaction getCoinbase(); MerkleBranch getChainMerkleBranch(); MerkleBranch getCoinbaseBranch(); Transaction getTransaction(); void setCoinbaseBranch(final MerkleBranch merkleBranch); void setParentBlockHeader(final AltcoinBlock header); static final byte[] MERGED_MINING_HEADER; }
@Test public void checkAuxPoWHeader() throws Exception { byte[] auxpowAsBytes = getBytes(getClass().getResourceAsStream("auxpow_header.bin")); AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, params.getDefaultSerializer()); auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"), Utils.decodeCompactBits(0x1b06f8f0), true); }
@Test public void checkAuxPoWHeaderNoTxHeader() throws Exception { final NetworkParameters namecoinLikeParams = new DogecoinTestNet3Params() { @Override public Sha256Hash getBlockDifficultyHash(Block block) { return block.getHash(); } }; byte[] auxpowAsBytes = getBytes(getClass().getResourceAsStream("auxpow_header_no_tx_header.bin")); AuxPoW auxpow = new AuxPoW(namecoinLikeParams, auxpowAsBytes, (ChildMessage) null, namecoinLikeParams.getDefaultSerializer()); auxpow.checkProofOfWork(Sha256Hash.wrap("5fb89c3b18c27bc38d351d516177cbd3504c95ca0494cbbbbd52f2fb5f2ff1ec"), Utils.decodeCompactBits(0x1b00b269), true); }
@Test public void shouldRejectHashAboveTarget() throws Exception { final byte[] auxpowAsBytes = getBytes(getClass().getResourceAsStream("auxpow_header.bin")); final AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, params.getDefaultSerializer()); expectedEx.expect(org.bitcoinj.core.VerificationException.class); expectedEx.expectMessage("Hash is higher than target: 000000000003178bb23160cdbc81af53f47cae9f479acf1e69849da42fd5bfca vs 0"); auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"), Utils.decodeCompactBits(0x00), true); }