mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-30 23:02:15 +00:00
Modify version handling to match Dogecoin 1.10 style API
Calling getVersion() on an AuxPoW block now returns the lowest 8 bits only, and a new getRawVersion() method is introduced to support fetching full version. Added unit tests to check unpacking of AuxPoW version numbers.
This commit is contained in:
parent
98ae05b0a1
commit
a2ba8da774
@ -26,12 +26,14 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.libdohj.core.ScryptHash;
|
||||
import static org.libdohj.core.Utils.scryptDigest;
|
||||
|
||||
import static org.bitcoinj.core.Utils.reverseBytes;
|
||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
||||
|
||||
/**
|
||||
* <p>A block is a group of transactions, and is one of the fundamental data structures of the Bitcoin system.
|
||||
@ -44,17 +46,18 @@ import static org.bitcoinj.core.Utils.reverseBytes;
|
||||
* specifically using {@link Peer#getBlock(Sha256Hash)}, or grab one from a downloaded {@link BlockChain}.
|
||||
*/
|
||||
public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
/** Bit used to indicate that a block contains an AuxPoW section, where the network supports AuxPoW */
|
||||
public static final int BLOCK_VERSION_CHAIN_START = (1 << 16);
|
||||
public static final int BLOCK_VERSION_CHAIN_END = (1 << 30);
|
||||
public static final int BLOCK_VERSION_AUXPOW = (1 << 8);
|
||||
|
||||
private boolean auxpowParsed = false;
|
||||
private boolean auxpowBytesValid = false;
|
||||
|
||||
/** AuxPoW header element, if applicable. */
|
||||
@Nullable private AuxPoW auxpow;
|
||||
|
||||
/**
|
||||
* Whether the chain this block belongs to support AuxPoW, used to avoid
|
||||
* repeated instanceof checks. Initialised in parseTransactions()
|
||||
*/
|
||||
private boolean auxpowChain = false;
|
||||
|
||||
private ScryptHash scryptHash;
|
||||
|
||||
/** Special case constructor, used for the genesis node, cloneAsHeader and unit tests. */
|
||||
@ -115,7 +118,6 @@ public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
}
|
||||
|
||||
public AuxPoW getAuxPoW() {
|
||||
// TODO: maybeParseAuxPoW();
|
||||
return this.auxpow;
|
||||
}
|
||||
|
||||
@ -136,14 +138,65 @@ public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
return getScryptHash().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chain ID (upper 16 bits) from an AuxPoW version number.
|
||||
*/
|
||||
public static long getChainID(final long rawVersion) {
|
||||
return rawVersion >> 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return chain ID from block version of an AuxPoW-enabled chain.
|
||||
*/
|
||||
public long getChainID() {
|
||||
return getChainID(this.getRawVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return flags from block version of an AuxPoW-enabled chain.
|
||||
*
|
||||
* @return flags as a bitset.
|
||||
*/
|
||||
public BitSet getVersionFlags() {
|
||||
return BitSet.valueOf(new long[] {(this.getRawVersion() & 0xff00) >> 8});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return block version without applying any filtering (i.e. for AuxPoW blocks
|
||||
* which structure version differently to pack in additional data).
|
||||
*/
|
||||
public final long getRawVersion() {
|
||||
return super.getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base version (i.e. Bitcoin-like version number) out of a packed
|
||||
* AuxPoW version number (i.e. one that contains chain ID and feature flags).
|
||||
*/
|
||||
public static long getBaseVersion(final long rawVersion) {
|
||||
return rawVersion & 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getVersion() {
|
||||
// TODO: Can we cache the individual parts on parse?
|
||||
if (this.params instanceof AltcoinNetworkParameters) {
|
||||
// AuxPoW networks use the higher block version bits for flags and
|
||||
// chain ID.
|
||||
return getBaseVersion(super.getVersion());
|
||||
} else {
|
||||
return super.getVersion();
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseAuxPoW() throws ProtocolException {
|
||||
if (this.auxpowParsed)
|
||||
return;
|
||||
|
||||
this.auxpow = null;
|
||||
if (this.params instanceof AltcoinNetworkParameters) {
|
||||
final AltcoinNetworkParameters altcoinParams = (AltcoinNetworkParameters)this.params;
|
||||
if (altcoinParams.isAuxPoWBlockVersion(this.getVersion())) {
|
||||
if (this.auxpowChain) {
|
||||
final AuxPoWNetworkParameters auxpowParams = (AuxPoWNetworkParameters)this.params;
|
||||
if (auxpowParams.isAuxPoWBlockVersion(this.getRawVersion())) {
|
||||
// The following is used in dogecoinj, but I don't think we necessarily need it
|
||||
// payload.length >= 160) { // We have at least 2 headers in an Aux block. Workaround for StoredBlocks
|
||||
this.auxpow = new AuxPoW(params, payload, cursor, this, serializer);
|
||||
@ -157,6 +210,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
|
||||
@Override
|
||||
protected void parseTransactions(final int offset) {
|
||||
this.auxpowChain = params instanceof AuxPoWNetworkParameters;
|
||||
parseAuxPoW();
|
||||
if (null != this.auxpow) {
|
||||
super.parseTransactions(offset + auxpow.getMessageSize());
|
||||
@ -176,7 +230,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
/** Returns a copy of the block, but without any transactions. */
|
||||
@Override
|
||||
public Block cloneAsHeader() {
|
||||
AltcoinBlock block = new AltcoinBlock(params, getVersion());
|
||||
AltcoinBlock block = new AltcoinBlock(params, getRawVersion());
|
||||
super.copyBitcoinHeaderTo(block);
|
||||
block.auxpow = auxpow;
|
||||
return block;
|
||||
@ -187,8 +241,8 @@ public class AltcoinBlock extends org.bitcoinj.core.Block {
|
||||
if (params instanceof AltcoinNetworkParameters) {
|
||||
BigInteger target = getDifficultyTargetAsInteger();
|
||||
|
||||
final AltcoinNetworkParameters altParams = (AltcoinNetworkParameters)auxpow;
|
||||
if (altParams.isAuxPoWBlockVersion(getVersion()) && null != auxpow) {
|
||||
final AuxPoWNetworkParameters altParams = (AuxPoWNetworkParameters)auxpow;
|
||||
if (altParams.isAuxPoWBlockVersion(getRawVersion()) && null != auxpow) {
|
||||
return auxpow.checkProofOfWork(this.getHash(), target, throwException);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import org.libdohj.core.AltcoinNetworkParameters;
|
||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -239,14 +239,14 @@ public class AuxPoW extends ChildMessage {
|
||||
*/
|
||||
protected boolean checkProofOfWork(Sha256Hash hashAuxBlock,
|
||||
BigInteger target, boolean throwException) throws VerificationException {
|
||||
if (!(params instanceof AltcoinNetworkParameters)) {
|
||||
if (!(params instanceof AuxPoWNetworkParameters)) {
|
||||
if (throwException) {
|
||||
// Should be impossible
|
||||
throw new VerificationException("Network parameters are not an instance of AltcoinNetworkParameters, AuxPoW support is not available.");
|
||||
throw new VerificationException("Network parameters are not an instance of AuxPoWNetworkParameters, AuxPoW support is not available.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
final AltcoinNetworkParameters altcoinParams = (AltcoinNetworkParameters) params;
|
||||
final AuxPoWNetworkParameters altcoinParams = (AuxPoWNetworkParameters) params;
|
||||
|
||||
if (0 != this.getCoinbaseBranch().getIndex()) {
|
||||
if (throwException) {
|
||||
@ -257,7 +257,7 @@ public class AuxPoW extends ChildMessage {
|
||||
}
|
||||
|
||||
if (!altcoinParams.isTestNet()
|
||||
&& getChainID(parentBlockHeader) == altcoinParams.getChainID()) {
|
||||
&& parentBlockHeader.getChainID() == altcoinParams.getChainID()) {
|
||||
if (throwException) {
|
||||
throw new VerificationException("Aux POW parent has our chain ID");
|
||||
}
|
||||
@ -362,7 +362,7 @@ public class AuxPoW extends ChildMessage {
|
||||
// for the same slot.
|
||||
long rand = nonce;
|
||||
rand = rand * 1103515245 + 12345;
|
||||
rand += ((AltcoinNetworkParameters) params).getChainID();
|
||||
rand += ((AuxPoWNetworkParameters) params).getChainID();
|
||||
rand = rand * 1103515245 + 12345;
|
||||
|
||||
if (getChainMerkleBranch().getIndex() != (rand % branchSize)) {
|
||||
@ -407,13 +407,6 @@ public class AuxPoW extends ChildMessage {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chain ID from a block header.
|
||||
*/
|
||||
public static long getChainID(final Block blockHeader) {
|
||||
return blockHeader.getVersion() / AltcoinBlock.BLOCK_VERSION_CHAIN_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the merkle branch used to connect the coinbase transaction to the
|
||||
* parent block header.
|
||||
|
@ -16,7 +16,7 @@ public class ConvertAddress {
|
||||
public static void main(final String[] argv) throws AddressFormatException {
|
||||
final NetworkParameters mainParams = MainNetParams.get();
|
||||
final NetworkParameters dogeParams = DogecoinMainNetParams.get();
|
||||
final Address address = Address.fromBase58(mainParams, "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L");
|
||||
final Address address = Address.fromBase58(mainParams, "175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W");
|
||||
final Address newAddress = new Address(dogeParams, 30, address.getHash160());
|
||||
|
||||
System.out.println(newAddress.toBase58());
|
||||
|
@ -20,14 +20,9 @@ import org.bitcoinj.core.Sha256Hash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jrn
|
||||
* @author Ross Nicoll
|
||||
*/
|
||||
public interface AltcoinNetworkParameters {
|
||||
|
||||
boolean isAuxPoWBlockVersion(long version);
|
||||
|
||||
int getChainID();
|
||||
|
||||
/**
|
||||
* Get the hash for the given block, for comparing against target difficulty.
|
||||
* This provides an extension hook for networks which use a hash other than
|
||||
|
27
src/main/java/org/libdohj/core/AuxPoWNetworkParameters.java
Normal file
27
src/main/java/org/libdohj/core/AuxPoWNetworkParameters.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 Ross Nicoll
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.libdohj.core;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ross Nicoll
|
||||
*/
|
||||
public interface AuxPoWNetworkParameters extends AltcoinNetworkParameters {
|
||||
|
||||
boolean isAuxPoWBlockVersion(long version);
|
||||
|
||||
int getChainID();
|
||||
}
|
@ -35,18 +35,19 @@ import org.bitcoinj.utils.MonetaryFormat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.libdohj.core.AltcoinSerializer;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionInput;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.libdohj.core.AltcoinSerializer;
|
||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
||||
|
||||
/**
|
||||
* Parameters for the main Dogecoin production network on which people trade goods and services.
|
||||
*/
|
||||
public abstract class AbstractDogecoinParams extends NetworkParameters implements AltcoinNetworkParameters {
|
||||
public abstract class AbstractDogecoinParams extends NetworkParameters implements AuxPoWNetworkParameters {
|
||||
/** Standard format for the DOGE denomination. */
|
||||
public static final MonetaryFormat DOGE;
|
||||
/** Standard format for the mDOGE denomination. */
|
||||
@ -69,9 +70,8 @@ public abstract class AbstractDogecoinParams extends NetworkParameters implement
|
||||
/** Currency code for base 1/100,000,000 Dogecoin. */
|
||||
public static final String CODE_KOINU = "Koinu";
|
||||
|
||||
public static final int BLOCK_VERSION_DEFAULT = 0x00000002;
|
||||
public static final int BLOCK_VERSION_AUXPOW = 0x00620002;
|
||||
public static final int BLOCK_VERSION_FLAG_AUXPOW = 0x00000100;
|
||||
private static final int BLOCK_MIN_VERSION_AUXPOW = 0x00620002;
|
||||
private static final int BLOCK_VERSION_FLAG_AUXPOW = 0x00000100;
|
||||
|
||||
static {
|
||||
DOGE = MonetaryFormat.BTC.noCode()
|
||||
@ -311,7 +311,7 @@ public abstract class AbstractDogecoinParams extends NetworkParameters implement
|
||||
|
||||
@Override
|
||||
public boolean isAuxPoWBlockVersion(long version) {
|
||||
return version >= BLOCK_VERSION_AUXPOW
|
||||
return version >= BLOCK_MIN_VERSION_AUXPOW
|
||||
&& (version & BLOCK_VERSION_FLAG_AUXPOW) > 0;
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,20 @@ package org.bitcoinj.core;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.libdohj.core.AltcoinSerializer;
|
||||
import org.libdohj.core.AuxPoWNetworkParameters;
|
||||
import org.libdohj.params.DogecoinMainNetParams;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.bitcoinj.core.Util.getBytes;
|
||||
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 org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
/**
|
||||
@ -97,7 +100,9 @@ public class AuxPoWTest {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block371337.bin"));
|
||||
AltcoinSerializer serializer = (AltcoinSerializer)params.getDefaultSerializer();
|
||||
final AltcoinBlock block = (AltcoinBlock)serializer.makeBlock(payload);
|
||||
assertEquals(98, block.getChainID());
|
||||
final AuxPoW auxpow = block.getAuxPoW();
|
||||
assertNotNull(auxpow);
|
||||
auxpow.setParentBlockHeader((AltcoinBlock)block.cloneAsHeader());
|
||||
expectedEx.expect(org.bitcoinj.core.VerificationException.class);
|
||||
expectedEx.expectMessage("Aux POW parent has our chain ID");
|
||||
|
@ -12,6 +12,7 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -27,6 +28,24 @@ public class DogecoinBlockTest {
|
||||
Context context = new Context(params);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldExtractChainID() {
|
||||
final long baseVersion = 2;
|
||||
final long flags = 1;
|
||||
final long chainID = 98;
|
||||
final long auxpowVersion = (chainID << 16) | (flags << 8) | baseVersion;
|
||||
assertEquals(chainID, AltcoinBlock.getChainID(auxpowVersion));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldExtractBaseVersion() {
|
||||
final long baseVersion = 2;
|
||||
final long flags = 1;
|
||||
final long chainID = 98;
|
||||
final long auxpowVersion = (chainID << 16) | (flags << 8) | baseVersion;
|
||||
assertEquals(baseVersion, AltcoinBlock.getBaseVersion(auxpowVersion));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseBlock1() throws IOException {
|
||||
byte[] payload = Util.getBytes(getClass().getResourceAsStream("dogecoin_block1.bin"));
|
||||
@ -65,6 +84,12 @@ public class DogecoinBlockTest {
|
||||
final AltcoinBlock block = (AltcoinBlock)serializer.makeBlock(payload);
|
||||
assertEquals("60323982f9c5ff1b5a954eac9dc1269352835f47c2c5222691d80f0d50dcf053", 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();
|
||||
@ -75,18 +100,18 @@ public class DogecoinBlockTest {
|
||||
|
||||
final MerkleBranch blockchainMerkleBranch = auxpow.getChainMerkleBranch();
|
||||
Sha256Hash[] expected = new Sha256Hash[] {
|
||||
new Sha256Hash("b541c848bc001d07d2bdf8643abab61d2c6ae50d5b2495815339a4b30703a46f"),
|
||||
new Sha256Hash("78d6abe48cee514cf3496f4042039acb7e27616dcfc5de926ff0d6c7e5987be7"),
|
||||
new Sha256Hash("a0469413ce64d67c43902d54ee3a380eff12ded22ca11cbd3842e15d48298103")
|
||||
Sha256Hash.wrap("b541c848bc001d07d2bdf8643abab61d2c6ae50d5b2495815339a4b30703a46f"),
|
||||
Sha256Hash.wrap("78d6abe48cee514cf3496f4042039acb7e27616dcfc5de926ff0d6c7e5987be7"),
|
||||
Sha256Hash.wrap("a0469413ce64d67c43902d54ee3a380eff12ded22ca11cbd3842e15d48298103")
|
||||
};
|
||||
|
||||
assertArrayEquals(expected, blockchainMerkleBranch.getHashes().toArray(new Sha256Hash[blockchainMerkleBranch.size()]));
|
||||
|
||||
final MerkleBranch coinbaseMerkleBranch = auxpow.getCoinbaseBranch();
|
||||
expected = new Sha256Hash[] {
|
||||
new Sha256Hash("cd3947cd5a0c26fde01b05a3aa3d7a38717be6ae11d27239365024db36a679a9"),
|
||||
new Sha256Hash("48f9e8fef3411944e27f49ec804462c9e124dca0954c71c8560e8a9dd218a452"),
|
||||
new Sha256Hash("d11293660392e7c51f69477a6130237c72ecee2d0c1d3dc815841734c370331a")
|
||||
Sha256Hash.wrap("cd3947cd5a0c26fde01b05a3aa3d7a38717be6ae11d27239365024db36a679a9"),
|
||||
Sha256Hash.wrap("48f9e8fef3411944e27f49ec804462c9e124dca0954c71c8560e8a9dd218a452"),
|
||||
Sha256Hash.wrap("d11293660392e7c51f69477a6130237c72ecee2d0c1d3dc815841734c370331a")
|
||||
};
|
||||
assertArrayEquals(expected, coinbaseMerkleBranch.getHashes().toArray(new Sha256Hash[coinbaseMerkleBranch.size()]));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user