mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-14 11:15:51 +00:00
Modify parsing of nonce value from AuxPoW coinbase transaction script to
use long values rather than int, to support Java correctly. Add unit tests for parsing of nonce values and calculating expected slot index for AuxPoW headers.
This commit is contained in:
parent
1a5184ab4b
commit
8a96492c80
@ -351,21 +351,9 @@ public class AuxPoW extends ChildMessage {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] nonceBytes = Utils.reverseBytes(Arrays.copyOfRange(script, pc + 4, pc + 8));
|
||||
int nonce = ByteBuffer.wrap(nonceBytes).getInt();
|
||||
long nonce = getNonceFromScript(script, pc);
|
||||
|
||||
// Choose a pseudo-random slot in the chain merkle tree
|
||||
// but have it be fixed for a size/nonce/chain combination.
|
||||
//
|
||||
// This prevents the same work from being used twice for the
|
||||
// same chain while reducing the chance that two chains clash
|
||||
// for the same slot.
|
||||
long rand = nonce;
|
||||
rand = rand * 1103515245 + 12345;
|
||||
rand += ((AuxPoWNetworkParameters) params).getChainID();
|
||||
rand = rand * 1103515245 + 12345;
|
||||
|
||||
if (getChainMerkleBranch().getIndex() != (rand % branchSize)) {
|
||||
if (getChainMerkleBranch().getIndex() != getExpectedIndex(nonce, ((AuxPoWNetworkParameters) params).getChainID(), getChainMerkleBranch().size())) {
|
||||
if (throwException) {
|
||||
throw new VerificationException("Aux POW wrong index");
|
||||
}
|
||||
@ -386,6 +374,42 @@ public class AuxPoW extends ChildMessage {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nonce value from the coinbase transaction script.
|
||||
*
|
||||
* @param script the transaction script to extract the nonce from.
|
||||
* @param pc offset of the merkle branch size within the script (this is 4
|
||||
* bytes before the start of the nonce value). Range checks should be
|
||||
* performed before calling this method.
|
||||
* @return the nonce value.
|
||||
*/
|
||||
protected static long getNonceFromScript(final byte[] script, int pc) {
|
||||
// Note that the nonce value is packed as platform order (typically
|
||||
// little-endian) so we have to convert to big-endian for Java
|
||||
final byte[] nonceBytes = Utils.reverseBytes(Arrays.copyOfRange(script, pc + 4, pc + 8));
|
||||
|
||||
return ByteBuffer.wrap(nonceBytes).getInt() & 0xffffffffl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expected index of the slot within the chain merkle tree.
|
||||
*
|
||||
* This prevents the same work from being used twice for the
|
||||
* same chain while reducing the chance that two chains clash
|
||||
* for the same slot.
|
||||
*/
|
||||
protected static int getExpectedIndex(final long nonce, final int chainId, final int merkleHeight) {
|
||||
// Choose a pseudo-random slot in the chain merkle tree
|
||||
// but have it be fixed for a size/nonce/chain combination.
|
||||
|
||||
long rand = nonce;
|
||||
rand = rand * 1103515245 + 12345;
|
||||
rand += chainId;
|
||||
rand = rand * 1103515245 + 12345;
|
||||
|
||||
return (int) (rand % (1L << merkleHeight));
|
||||
}
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
@ -398,7 +422,7 @@ public class AuxPoW extends ChildMessage {
|
||||
* @param subArray the shorter array to test for presence in the longer array.
|
||||
* @return true if the shorter array is present at the offset, false otherwise.
|
||||
*/
|
||||
private boolean arrayMatch(byte[] script, int offset, byte[] subArray) {
|
||||
static boolean arrayMatch(byte[] script, int offset, byte[] subArray) {
|
||||
for (int matchIdx = 0; matchIdx + offset < script.length && matchIdx < subArray.length; matchIdx++) {
|
||||
if (script[offset + matchIdx] != subArray[matchIdx]) {
|
||||
return false;
|
||||
|
@ -1,7 +1,10 @@
|
||||
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;
|
||||
@ -13,6 +16,7 @@ import static org.bitcoinj.core.Utils.reverseBytes;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@ -360,4 +364,32 @@ public class AuxPoWTest {
|
||||
auxpow.setCoinbaseBranch(new MerkleBranch(params, auxpow,
|
||||
Collections.singletonList(revisedCoinbaseHash), MERKLE_ROOT_COINBASE_INDEX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test extraction of a nonce value from the coinbase transaction pubscript.
|
||||
* This test primarily exists to ensure that byte order is correct, and that
|
||||
* a nonce value above Integer.MAX_VALUE is still returned as a positive
|
||||
* integer.
|
||||
*/
|
||||
@Test
|
||||
public void testGetNonceFromScript() {
|
||||
final byte[] script = Utils.HEX.decode("03251d0de4b883e5bda9e7a59ee4bb99e9b1bcfabe6d6dc6c83f297ee373df0d826f3148f218e4e4eb349e0bba715ad793ccc2d6beb6df40000000f09f909f4d696e65642062792079616e6779616e676368656e00000000000000000000000000000000");
|
||||
final int pc = 55;
|
||||
final long expResult = 0x9f909ff0L;
|
||||
final long result = AuxPoW.getNonceFromScript(script, pc);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of getExpectedIndex method, of class AuxPoW.
|
||||
*/
|
||||
@Test
|
||||
public void testGetExpectedIndex() {
|
||||
final long nonce = 0x9f909ff0L;
|
||||
final int chainId = 98;
|
||||
final int merkleHeight = 6;
|
||||
final int expResult = 40;
|
||||
final int result = AuxPoW.getExpectedIndex(nonce, chainId, merkleHeight);
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package org.bitcoinj.core;
|
||||
|
||||
import org.libdohj.core.AltcoinSerializer;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import org.libdohj.params.DogecoinMainNetParams;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@ -116,6 +117,35 @@ public class DogecoinBlockTest {
|
||||
assertArrayEquals(expected, coinbaseMerkleBranch.getHashes().toArray(new Sha256Hash[coinbaseMerkleBranch.size()]));
|
||||
|
||||
assertEquals(6, block.getTransactions().size());
|
||||
|
||||
assertTrue(auxpow.checkProofOfWork(block.getHash(), block.getDifficultyTargetAsInteger(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm parsing of block with a nonce value above Integer.MAX_VALUE.
|
||||
* See https://github.com/rnicoll/libdohj/issues/5
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void shouldParseBlock894863() throws IOException {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block894863.bin"));
|
||||
AltcoinSerializer serializer = (AltcoinSerializer)params.getDefaultSerializer();
|
||||
final AltcoinBlock block = (AltcoinBlock)serializer.makeBlock(payload);
|
||||
assertEquals("93a207e6d227f4d60ee64fad584b47255f654b0b6378d78e774123dd66f4fef9", block.getHashAsString());
|
||||
assertEquals(0, block.getNonce());
|
||||
|
||||
// Check block version values
|
||||
assertEquals(2, block.getVersion());
|
||||
assertEquals(98, block.getChainID());
|
||||
assertTrue(block.getVersionFlags().get(0));
|
||||
|
||||
final AuxPoW auxpow = block.getAuxPoW();
|
||||
assertNotNull(auxpow);
|
||||
final Transaction auxpowCoinbase = auxpow.getCoinbase();
|
||||
assertEquals("c84431cf41f592373cc70db07f6804f945202f5f7baad31a8bbab89aaecb7b8b", auxpowCoinbase.getHashAsString());
|
||||
|
||||
assertTrue(auxpow.checkProofOfWork(block.getHash(), block.getDifficultyTargetAsInteger(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block894863.bin
Normal file
BIN
src/test/resources/org/bitcoinj/core/dogecoin_block894863.bin
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user