mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-11 17:55:53 +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]
|
(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 Logger log = LoggerFactory.getLogger(AuxPoW.class);
|
||||||
private static final long serialVersionUID = -8567546957352643140L;
|
private static final long serialVersionUID = -8567546957352643140L;
|
||||||
|
|
||||||
@ -290,44 +296,49 @@ public class AuxPoW extends ChildMessage {
|
|||||||
|
|
||||||
// Check that the same work is not submitted twice to our chain, by
|
// 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
|
// confirming that the child block hash is in the coinbase merkle tree
|
||||||
int pcHeader = -1;
|
int pcHead = -1;
|
||||||
int pc = -1;
|
int pc = -1;
|
||||||
|
|
||||||
for (int scriptIdx = 0; scriptIdx < script.length; scriptIdx++) {
|
for (int scriptIdx = 0; scriptIdx < script.length; scriptIdx++) {
|
||||||
if (arrayMatch(script, scriptIdx, MERGED_MINING_HEADER)) {
|
if (arrayMatch(script, scriptIdx, MERGED_MINING_HEADER)) {
|
||||||
// Enforce only one chain merkle root by checking that a single instance of the merged
|
// Enforce only one chain merkle root by checking that a single instance of the merged
|
||||||
// mining header exists just before.
|
// mining header exists just before.
|
||||||
if (pcHeader >= 0) {
|
if (pcHead >= 0) {
|
||||||
if (throwException) {
|
if (throwException) {
|
||||||
throw new VerificationException("Multiple merged mining headers in coinbase");
|
throw new VerificationException("Multiple merged mining headers in coinbase");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pcHeader = scriptIdx;
|
pcHead = scriptIdx;
|
||||||
} else if (arrayMatch(script, scriptIdx, vchRootHash)) {
|
} else if (arrayMatch(script, scriptIdx, vchRootHash)) {
|
||||||
pc = scriptIdx;
|
pc = scriptIdx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == pcHeader) {
|
if (pc == -1) {
|
||||||
if (throwException) {
|
|
||||||
throw new VerificationException("MergedMiningHeader missing from parent coinbase");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-1 == pc) {
|
|
||||||
if (throwException) {
|
if (throwException) {
|
||||||
throw new VerificationException("Aux POW missing chain merkle root in parent coinbase");
|
throw new VerificationException("Aux POW missing chain merkle root in parent coinbase");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcHeader + MERGED_MINING_HEADER.length != pc) {
|
if (pcHead != -1) {
|
||||||
if (throwException) {
|
if (pcHead + MERGED_MINING_HEADER.length != pc) {
|
||||||
throw new VerificationException("Merged mining header is not just before chain merkle root");
|
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;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we are at a deterministic point in the merkle leaves by hashing
|
// Ensure we are at a deterministic point in the merkle leaves by hashing
|
||||||
@ -361,12 +372,12 @@ public class AuxPoW extends ChildMessage {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInteger h = altcoinParams.getBlockDifficultyHash(getParentBlockHeader())
|
Sha256Hash hash = altcoinParams.getBlockDifficultyHash(getParentBlockHeader());
|
||||||
.toBigInteger();
|
BigInteger hashVal = hash.toBigInteger();
|
||||||
if (h.compareTo(target) > 0) {
|
if (hashVal.compareTo(target) > 0) {
|
||||||
// Proof of work check failed!
|
// Proof of work check failed!
|
||||||
if (throwException) {
|
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));
|
+ target.toString(16));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
package org.bitcoinj.core;
|
package org.bitcoinj.core;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import static org.bitcoinj.core.AuxPoW.MERGED_MINING_HEADER;
|
|
||||||
|
|
||||||
import org.libdohj.core.AltcoinSerializer;
|
import org.libdohj.core.AltcoinSerializer;
|
||||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
|
||||||
import org.libdohj.params.DogecoinMainNetParams;
|
import org.libdohj.params.DogecoinMainNetParams;
|
||||||
|
import org.libdohj.params.DogecoinTestNet3Params;
|
||||||
|
|
||||||
import static org.bitcoinj.core.Util.getBytes;
|
import static org.bitcoinj.core.Util.getBytes;
|
||||||
import static org.bitcoinj.core.Utils.reverseBytes;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -74,6 +70,26 @@ public class AuxPoWTest {
|
|||||||
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
||||||
Utils.decodeCompactBits(0x1b06f8f0), true);
|
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
|
@Rule
|
||||||
public ExpectedException expectedEx = ExpectedException.none();
|
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
|
* Catch the case that the coinbase transaction does not contain details of
|
||||||
* transaction.
|
* the merged block. In this case we make the transaction script too short
|
||||||
|
* for it to do so.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldRejectIfMergedMineHeaderMissing() throws Exception {
|
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
|
// This will also break the difficulty check, but as that doesn't occur
|
||||||
// until the end, we can get away with it.
|
// until the end, we can get away with it.
|
||||||
final TransactionInput in = auxpow.getCoinbase().getInput(0);
|
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);
|
updateMerkleRootToMatchCoinbase(auxpow);
|
||||||
|
|
||||||
expectedEx.expect(org.bitcoinj.core.VerificationException.class);
|
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"),
|
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
||||||
Utils.decodeCompactBits(0x1b06f8f0), true);
|
Utils.decodeCompactBits(0x1b06f8f0), true);
|
||||||
}
|
}
|
||||||
@ -337,7 +357,7 @@ public class AuxPoWTest {
|
|||||||
final AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, params.getDefaultSerializer());
|
final AuxPoW auxpow = new AuxPoW(params, auxpowAsBytes, (ChildMessage) null, params.getDefaultSerializer());
|
||||||
|
|
||||||
expectedEx.expect(org.bitcoinj.core.VerificationException.class);
|
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"),
|
auxpow.checkProofOfWork(Sha256Hash.wrap("0c836b86991631d34a8a68054e2f62db919b39d1ee43c27ab3344d6aa82fa609"),
|
||||||
Utils.decodeCompactBits(0x00), true);
|
Utils.decodeCompactBits(0x00), true);
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user