mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-07 06:44:16 +00:00
Handle legacy AuxPoW blocks
Adds handling of legacy AuxPoW blocks before there was a merged mining header.
This commit is contained in:
parent
9afda0e8e9
commit
89cf3c6b17
@ -41,6 +41,12 @@ public class AuxPoW extends ChildMessage {
|
||||
(byte) 0xfa, (byte) 0xbe, "m".getBytes()[0], "m".getBytes()[0]
|
||||
};
|
||||
|
||||
/**
|
||||
* Maximum index of the merkle root hash in the coinbase transaction script,
|
||||
* where no merged mining header is present.
|
||||
*/
|
||||
protected static final int MAX_INDEX_PC_BACKWARDS_COMPATIBILITY = 20;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AuxPoW.class);
|
||||
private static final long serialVersionUID = -8567546957352643140L;
|
||||
|
||||
@ -290,45 +296,50 @@ public class AuxPoW extends ChildMessage {
|
||||
|
||||
// Check that the same work is not submitted twice to our chain, by
|
||||
// confirming that the child block hash is in the coinbase merkle tree
|
||||
int pcHeader = -1;
|
||||
int pcHead = -1;
|
||||
int pc = -1;
|
||||
|
||||
for (int scriptIdx = 0; scriptIdx < script.length; scriptIdx++) {
|
||||
if (arrayMatch(script, scriptIdx, MERGED_MINING_HEADER)) {
|
||||
// Enforce only one chain merkle root by checking that a single instance of the merged
|
||||
// mining header exists just before.
|
||||
if (pcHeader >= 0) {
|
||||
if (pcHead >= 0) {
|
||||
if (throwException) {
|
||||
throw new VerificationException("Multiple merged mining headers in coinbase");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
pcHeader = scriptIdx;
|
||||
pcHead = scriptIdx;
|
||||
} else if (arrayMatch(script, scriptIdx, vchRootHash)) {
|
||||
pc = scriptIdx;
|
||||
}
|
||||
}
|
||||
|
||||
if (-1 == pcHeader) {
|
||||
if (throwException) {
|
||||
throw new VerificationException("MergedMiningHeader missing from parent coinbase");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (-1 == pc) {
|
||||
if (pc == -1) {
|
||||
if (throwException) {
|
||||
throw new VerificationException("Aux POW missing chain merkle root in parent coinbase");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pcHeader + MERGED_MINING_HEADER.length != pc) {
|
||||
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 {
|
||||
// For backward compatibility.
|
||||
// Enforce only one chain merkle root by checking that it starts early in the coinbase.
|
||||
// 8-12 bytes are enough to encode extraNonce and nBits.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we are at a deterministic point in the merkle leaves by hashing
|
||||
// a nonce and our chain ID and comparing to the index.
|
||||
@ -361,12 +372,12 @@ public class AuxPoW extends ChildMessage {
|
||||
return false;
|
||||
}
|
||||
|
||||
BigInteger h = altcoinParams.getBlockDifficultyHash(getParentBlockHeader())
|
||||
.toBigInteger();
|
||||
if (h.compareTo(target) > 0) {
|
||||
Sha256Hash hash = altcoinParams.getBlockDifficultyHash(getParentBlockHeader());
|
||||
BigInteger hashVal = hash.toBigInteger();
|
||||
if (hashVal.compareTo(target) > 0) {
|
||||
// Proof of work check failed!
|
||||
if (throwException) {
|
||||
throw new VerificationException("Hash is higher than target: " + getParentBlockHeader().getHashAsString() + " vs "
|
||||
throw new VerificationException("Hash is higher than target: " + hash.toString() + " vs "
|
||||
+ target.toString(16));
|
||||
}
|
||||
return false;
|
||||
|
@ -1,17 +1,13 @@
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import static org.bitcoinj.core.AuxPoW.MERGED_MINING_HEADER;
|
||||
|
||||
import org.libdohj.core.AltcoinSerializer;
|
||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
||||
import org.libdohj.params.DogecoinMainNetParams;
|
||||
import org.libdohj.params.DogecoinTestNet3Params;
|
||||
|
||||
import static org.bitcoinj.core.Util.getBytes;
|
||||
import static org.bitcoinj.core.Utils.reverseBytes;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
@ -75,6 +71,26 @@ public class AuxPoWTest {
|
||||
Utils.decodeCompactBits(0x1b06f8f0), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the AuxPoW header with no explicit data header in the coinbase
|
||||
* transaction. Namecoin block #19,414
|
||||
*/
|
||||
@Test
|
||||
public void checkAuxPoWHeaderNoTxHeader() throws Exception {
|
||||
// Emulate Namecoin block hashing for this test
|
||||
final NetworkParameters namecoinLikeParams = new DogecoinTestNet3Params() {
|
||||
@Override
|
||||
public Sha256Hash getBlockDifficultyHash(Block block) {
|
||||
// Namecoin uses SHA256 hashes
|
||||
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);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedEx = ExpectedException.none();
|
||||
|
||||
@ -164,8 +180,9 @@ public class AuxPoWTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch the case that the merged mine header is missing from the coinbase
|
||||
* transaction.
|
||||
* Catch the case that the coinbase transaction does not contain details of
|
||||
* the merged block. In this case we make the transaction script too short
|
||||
* for it to do so.
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectIfMergedMineHeaderMissing() throws Exception {
|
||||
@ -175,11 +192,14 @@ public class AuxPoWTest {
|
||||
// This will also break the difficulty check, but as that doesn't occur
|
||||
// until the end, we can get away with it.
|
||||
final TransactionInput in = auxpow.getCoinbase().getInput(0);
|
||||
in.getScriptBytes()[4] = 0; // Break the first byte of the header
|
||||
final byte[] paddedScriptBytes = new byte[in.getScriptBytes().length + (AuxPoW.MAX_INDEX_PC_BACKWARDS_COMPATIBILITY + 4)];
|
||||
Arrays.fill(paddedScriptBytes, (byte) 0);
|
||||
System.arraycopy(in.getScriptBytes(), 8, paddedScriptBytes, (AuxPoW.MAX_INDEX_PC_BACKWARDS_COMPATIBILITY + 4), in.getScriptBytes().length - 8);
|
||||
in.setScriptBytes(paddedScriptBytes);
|
||||
updateMerkleRootToMatchCoinbase(auxpow);
|
||||
|
||||
expectedEx.expect(org.bitcoinj.core.VerificationException.class);
|
||||
expectedEx.expectMessage("MergedMiningHeader missing from parent coinbase");
|
||||
expectedEx.expectMessage("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
|
||||
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
||||
Utils.decodeCompactBits(0x1b06f8f0), true);
|
||||
}
|
||||
@ -337,7 +357,7 @@ public class AuxPoWTest {
|
||||
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: a22a9b01671d639fa6389f62ecf8ce69204c8ed41d5f1a745e0c5ba7116d5b4c vs 0");
|
||||
expectedEx.expectMessage("Hash is higher than target: 000000000003178bb23160cdbc81af53f47cae9f479acf1e69849da42fd5bfca vs 0");
|
||||
|
||||
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
||||
Utils.decodeCompactBits(0x00), true);
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user