mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-11 17:55:53 +00:00
Added network parameters for Namecoin (abstract and mainnet).
This commit is contained in:
parent
bacc348541
commit
0cb659ca21
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 2016 Jeremy Rand.
|
||||
*
|
||||
* 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.params;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
import org.bitcoinj.core.AltcoinBlock;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import static org.bitcoinj.core.Coin.COIN;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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;
|
||||
|
||||
// TODO: review this
|
||||
|
||||
/**
|
||||
* Common parameters for Namecoin networks.
|
||||
*/
|
||||
public abstract class AbstractNamecoinParams extends NetworkParameters implements AuxPoWNetworkParameters {
|
||||
/** Standard format for the NMC denomination. */
|
||||
public static final MonetaryFormat NMC;
|
||||
/** Standard format for the mNMC denomination. */
|
||||
public static final MonetaryFormat MNMC;
|
||||
/** Standard format for the uBTC denomination. */
|
||||
public static final MonetaryFormat UNMC;
|
||||
|
||||
public static final int AUXPOW_CHAIN_ID = 0x0001; // 1
|
||||
|
||||
/** Currency code for base 1 Namecoin. */
|
||||
public static final String CODE_NMC = "NMC";
|
||||
/** Currency code for base 1/1,000 Namecoin. */
|
||||
public static final String CODE_MNMC = "mNMC";
|
||||
/** Currency code for base 1/1,000,000 Namecoin. */
|
||||
public static final String CODE_UNMC = "µNMC";
|
||||
|
||||
protected int auxpowStartHeight;
|
||||
|
||||
private static final int BLOCK_VERSION_FLAG_AUXPOW = 0x00000100;
|
||||
|
||||
static {
|
||||
NMC = MonetaryFormat.BTC.noCode()
|
||||
.code(0, CODE_NMC)
|
||||
.code(3, CODE_MNMC)
|
||||
.code(6, CODE_UNMC);
|
||||
MNMC = NMC.shift(3).minDecimals(2).optionalDecimals(2);
|
||||
UNMC = NMC.shift(6).minDecimals(0).optionalDecimals(0);
|
||||
}
|
||||
|
||||
/** The string returned by getId() for the main, production network where people trade things. */
|
||||
public static final String ID_NMC_MAINNET = "org.namecoin.production";
|
||||
/** The string returned by getId() for the testnet. */
|
||||
public static final String ID_NMC_TESTNET = "org.namecoin.test";
|
||||
|
||||
protected Logger log = LoggerFactory.getLogger(AbstractNamecoinParams.class);
|
||||
|
||||
public static final int NAMECOIN_PROTOCOL_VERSION_GETHEADERS = 38000;
|
||||
|
||||
public AbstractNamecoinParams() {
|
||||
super();
|
||||
genesisBlock = createGenesis(this);
|
||||
interval = INTERVAL;
|
||||
targetTimespan = TARGET_TIMESPAN;
|
||||
maxTarget = Utils.decodeCompactBits(0x1e0fffffL); // TODO: figure out the Namecoin value of this
|
||||
|
||||
// BIP 43 recommends using these values regardless of which blockchain is in use.
|
||||
bip32HeaderPub = 0x0488B21E; //The 4 byte header that serializes in base58 to "xpub".
|
||||
bip32HeaderPriv = 0x0488ADE4; //The 4 byte header that serializes in base58 to "xprv"
|
||||
}
|
||||
|
||||
private static AltcoinBlock createGenesis(NetworkParameters params) {
|
||||
AltcoinBlock genesisBlock = new AltcoinBlock(params, Block.BLOCK_VERSION_GENESIS);
|
||||
Transaction t = new Transaction(params);
|
||||
try {
|
||||
// "... choose what comes next. Lives of your own, or a return to chains. -- V"
|
||||
byte[] bytes = Utils.HEX.decode
|
||||
("04ff7f001c020a024b2e2e2e2063686f6f7365207768617420636f6d6573206e6578742e20204c69766573206f6620796f7572206f776e2c206f7220612072657475726e20746f20636861696e732e202d2d2056");
|
||||
t.addInput(new TransactionInput(params, t, bytes));
|
||||
ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
|
||||
Script.writeBytes(scriptPubKeyBytes, Utils.HEX.decode
|
||||
("04b620369050cd899ffbbc4e8ee51e8c4534a855bb463439d63d235d4779685d8b6f4870a238cf365ac94fa13ef9a2a22cd99d0d5ee86dcabcafce36c7acf43ce5"));
|
||||
scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
|
||||
t.addOutput(new TransactionOutput(params, t, COIN.multiply(50), scriptPubKeyBytes.toByteArray()));
|
||||
} catch (Exception e) {
|
||||
// Cannot happen.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
genesisBlock.addTransaction(t);
|
||||
return genesisBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getBlockSubsidy(final int height) {
|
||||
return COIN.multiply(50).shiftRight(height / getSubsidyDecreaseBlockCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonetaryFormat getMonetaryFormat() {
|
||||
return NMC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Coin getMaxMoney() {
|
||||
return MAX_MONEY;
|
||||
}
|
||||
|
||||
// TODO: this is Bitcoin, need to figure out if it's the same for Namecoin
|
||||
@Override
|
||||
public Coin getMinNonDustOutput() {
|
||||
return Transaction.MIN_NONDUST_OUTPUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriScheme() {
|
||||
return "namecoin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMaxMoney() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is copied from Bitcoin
|
||||
/**
|
||||
* Checks if we are at a difficulty transition point.
|
||||
* @param storedPrev The previous stored block
|
||||
* @return If this is a difficulty transition point
|
||||
*/
|
||||
protected boolean isDifficultyTransitionPoint(StoredBlock storedPrev) {
|
||||
return ((storedPrev.getHeight() + 1) % this.getInterval()) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkDifficultyTransitions(StoredBlock storedPrev, Block nextBlock, BlockStore blockStore)
|
||||
throws VerificationException, BlockStoreException {
|
||||
// This is copied verbatim from Bitcoin except for the Namecoin changes marked accordingly
|
||||
Block prev = storedPrev.getHeader();
|
||||
|
||||
// Is this supposed to be a difficulty transition point?
|
||||
if (!isDifficultyTransitionPoint(storedPrev)) {
|
||||
|
||||
// No ... so check the difficulty didn't actually change.
|
||||
if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||
": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " +
|
||||
Long.toHexString(prev.getDifficultyTarget()));
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
|
||||
// two weeks after the initial block chain download.
|
||||
final Stopwatch watch = Stopwatch.createStarted();
|
||||
StoredBlock cursor = blockStore.get(prev.getHash());
|
||||
|
||||
// Namecoin addition
|
||||
int blocksBack = this.getInterval() - 1;
|
||||
if (storedPrev.getHeight() >= this.getAuxpowStartHeight() && (storedPrev.getHeight() + 1 > this.getInterval())) {
|
||||
blocksBack = this.getInterval();
|
||||
}
|
||||
|
||||
// Namecoin modification
|
||||
//for (int i = 0; i < this.getInterval() - 1; i++) {
|
||||
for (int i = 0; i < blocksBack; i++) {
|
||||
if (cursor == null) {
|
||||
// This should never happen. If it does, it means we are following an incorrect or busted chain.
|
||||
throw new VerificationException(
|
||||
"Difficulty transition point but we did not find a way back to the genesis block.");
|
||||
}
|
||||
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
||||
}
|
||||
watch.stop();
|
||||
if (watch.elapsed(TimeUnit.MILLISECONDS) > 50)
|
||||
log.info("Difficulty transition traversal took {}", watch);
|
||||
|
||||
Block blockIntervalAgo = cursor.getHeader();
|
||||
int timespan = (int) (prev.getTimeSeconds() - blockIntervalAgo.getTimeSeconds());
|
||||
// Limit the adjustment step.
|
||||
final int targetTimespan = this.getTargetTimespan();
|
||||
if (timespan < targetTimespan / 4)
|
||||
timespan = targetTimespan / 4;
|
||||
if (timespan > targetTimespan * 4)
|
||||
timespan = targetTimespan * 4;
|
||||
|
||||
BigInteger newTarget = Utils.decodeCompactBits(prev.getDifficultyTarget());
|
||||
newTarget = newTarget.multiply(BigInteger.valueOf(timespan));
|
||||
newTarget = newTarget.divide(BigInteger.valueOf(targetTimespan));
|
||||
|
||||
if (newTarget.compareTo(this.getMaxTarget()) > 0) {
|
||||
log.info("Difficulty hit proof of work limit: {}", newTarget.toString(16));
|
||||
newTarget = this.getMaxTarget();
|
||||
}
|
||||
|
||||
int accuracyBytes = (int) (nextBlock.getDifficultyTarget() >>> 24) - 3;
|
||||
long receivedTargetCompact = nextBlock.getDifficultyTarget();
|
||||
|
||||
// The calculated difficulty is to a higher precision than received, so reduce here.
|
||||
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
||||
newTarget = newTarget.and(mask);
|
||||
long newTargetCompact = Utils.encodeCompactBits(newTarget);
|
||||
|
||||
if (newTargetCompact != receivedTargetCompact)
|
||||
throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
|
||||
Long.toHexString(newTargetCompact) + " vs " + Long.toHexString(receivedTargetCompact));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChainID() {
|
||||
return AUXPOW_CHAIN_ID;
|
||||
}
|
||||
|
||||
// TODO: re-add this when we introduce Testnet2
|
||||
/**
|
||||
* Whether this network has special rules to enable minimum difficulty blocks
|
||||
* after a long interval between two blocks (i.e. testnet).
|
||||
*/
|
||||
//public abstract boolean allowMinDifficultyBlocks();
|
||||
|
||||
/**
|
||||
* Get the hash to use for a block.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Sha256Hash getBlockDifficultyHash(Block block) {
|
||||
return block.getHash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AltcoinSerializer getSerializer(boolean parseRetain) {
|
||||
return new AltcoinSerializer(this, parseRetain);
|
||||
}
|
||||
|
||||
// TODO: look into allowing PeerGroups that don't support GetHeaders (since for full block retrieval it's not needed)
|
||||
@Override
|
||||
public int getProtocolVersionNum(final ProtocolVersion version) {
|
||||
switch (version) {
|
||||
case MINIMUM:
|
||||
return NAMECOIN_PROTOCOL_VERSION_GETHEADERS;
|
||||
default:
|
||||
return version.getBitcoinProtocolVersion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuxPoWBlockVersion(long version) {
|
||||
return (version & BLOCK_VERSION_FLAG_AUXPOW) > 0;
|
||||
}
|
||||
|
||||
public int getAuxpowStartHeight() {
|
||||
return auxpowStartHeight;
|
||||
}
|
||||
|
||||
private static class CheckpointEncounteredException extends Exception {
|
||||
|
||||
private CheckpointEncounteredException() {
|
||||
}
|
||||
}
|
||||
}
|
120
core/src/main/java/org/libdohj/params/NamecoinMainNetParams.java
Normal file
120
core/src/main/java/org/libdohj/params/NamecoinMainNetParams.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc, 2016 Jeremy Rand.
|
||||
*
|
||||
* 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.params;
|
||||
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
// TODO: review this
|
||||
|
||||
/**
|
||||
* Parameters for the main Namecoin production network on which people trade
|
||||
* goods and services.
|
||||
*/
|
||||
public class NamecoinMainNetParams extends AbstractNamecoinParams {
|
||||
public static final int MAINNET_MAJORITY_WINDOW = 1000;
|
||||
public static final int MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED = 950;
|
||||
public static final int MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = 750;
|
||||
|
||||
public NamecoinMainNetParams() {
|
||||
super();
|
||||
dumpedPrivateKeyHeader = 180; //This is always addressHeader + 128
|
||||
addressHeader = 52;
|
||||
p2shHeader = 13;
|
||||
//acceptableAddressCodes = new int[] { addressHeader, p2shHeader };
|
||||
acceptableAddressCodes = new int[] { addressHeader }; // Namecoin doesn't yet enforce P2SH, so we disable it for now.
|
||||
port = 8334;
|
||||
packetMagic = 0xf9beb4fe;
|
||||
|
||||
genesisBlock.setDifficultyTarget(0x1C007FFFL);
|
||||
genesisBlock.setTime(1303000001L);
|
||||
genesisBlock.setNonce(2719916434L);
|
||||
id = ID_NMC_MAINNET;
|
||||
subsidyDecreaseBlockCount = 210000;
|
||||
spendableCoinbaseDepth = 100;
|
||||
auxpowStartHeight = 19200;
|
||||
|
||||
String genesisHash = genesisBlock.getHashAsString();
|
||||
checkState(genesisHash.equals("000000000062b72c5e2ceb45fbc8587e807c155b0da735e6483dfba2f0a9c770"),
|
||||
genesisHash);
|
||||
// TODO: remove alert key since it's removed from Bitcoin Core / Namecoin Core
|
||||
alertSigningKey = Hex.decode("04ba207043c1575208f08ea6ac27ed2aedd4f84e70b874db129acb08e6109a3bbb7c479ae22565973ebf0ac0391514511a22cb9345bdb772be20cfbd38be578b0c");
|
||||
|
||||
majorityEnforceBlockUpgrade = MAINNET_MAJORITY_ENFORCE_BLOCK_UPGRADE;
|
||||
majorityRejectBlockOutdated = MAINNET_MAJORITY_REJECT_BLOCK_OUTDATED;
|
||||
majorityWindow = MAINNET_MAJORITY_WINDOW;
|
||||
|
||||
// TODO: check whether there are any non BIP30 blocks in Namecoin; add them here if they exist
|
||||
// This contains (at a minimum) the blocks which are not BIP30 compliant. BIP30 changed how duplicate
|
||||
// transactions are handled. Duplicated transactions could occur in the case where a coinbase had the same
|
||||
// extraNonce and the same outputs but appeared at different heights, and greatly complicated re-org handling.
|
||||
// Having these here simplifies block connection logic considerably.
|
||||
checkpoints.put( 2016, Sha256Hash.wrap("0000000000660bad0d9fbde55ba7ee14ddf766ed5f527e3fbca523ac11460b92"));
|
||||
checkpoints.put( 4032, Sha256Hash.wrap("0000000000493b5696ad482deb79da835fe2385304b841beef1938655ddbc411"));
|
||||
checkpoints.put( 6048, Sha256Hash.wrap("000000000027939a2e1d8bb63f36c47da858e56d570f143e67e85068943470c9"));
|
||||
checkpoints.put( 8064, Sha256Hash.wrap("000000000003a01f708da7396e54d081701ea406ed163e519589717d8b7c95a5"));
|
||||
checkpoints.put( 10080, Sha256Hash.wrap("00000000000fed3899f818b2228b4f01b9a0a7eeee907abd172852df71c64b06"));
|
||||
checkpoints.put( 12096, Sha256Hash.wrap("0000000000006c06988ff361f124314f9f4bb45b6997d90a7ee4cedf434c670f"));
|
||||
checkpoints.put( 14112, Sha256Hash.wrap("00000000000045d95e0588c47c17d593c7b5cb4fb1e56213d1b3843c1773df2b"));
|
||||
checkpoints.put( 16128, Sha256Hash.wrap("000000000001d9964f9483f9096cf9d6c6c2886ed1e5dec95ad2aeec3ce72fa9"));
|
||||
checkpoints.put( 18940, Sha256Hash.wrap("00000000000087f7fc0c8085217503ba86f796fa4984f7e5a08b6c4c12906c05"));
|
||||
checkpoints.put( 30240, Sha256Hash.wrap("e1c8c862ff342358384d4c22fa6ea5f669f3e1cdcf34111f8017371c3c0be1da"));
|
||||
checkpoints.put( 57000, Sha256Hash.wrap("aa3ec60168a0200799e362e2b572ee01f3c3852030d07d036e0aa884ec61f203"));
|
||||
checkpoints.put(112896, Sha256Hash.wrap("73f880e78a04dd6a31efc8abf7ca5db4e262c4ae130d559730d6ccb8808095bf"));
|
||||
checkpoints.put(182000, Sha256Hash.wrap("d47b4a8fd282f635d66ce34ebbeb26ffd64c35b41f286646598abfd813cba6d9"));
|
||||
checkpoints.put(193000, Sha256Hash.wrap("3b85e70ba7f5433049cfbcf0ae35ed869496dbedcd1c0fafadb0284ec81d7b58"));
|
||||
|
||||
dnsSeeds = new String[] {
|
||||
"namecoindnsseed.digi-masters.com", // George Lloyd
|
||||
"namecoindnsseed.digi-masters.uk", // George Lloyd
|
||||
"seed.namecoin.domob.eu", // Daniel Kraft
|
||||
"nmc.seed.quisquis.de", // Peter Conrad
|
||||
"dnsseed.namecoin.webbtc.com", // Marius Hanne
|
||||
};
|
||||
|
||||
// TODO: look into HTTP seeds or Addr seeds as is done for Bitcoin
|
||||
}
|
||||
|
||||
private static NamecoinMainNetParams instance;
|
||||
public static synchronized NamecoinMainNetParams get() {
|
||||
if (instance == null) {
|
||||
instance = new NamecoinMainNetParams();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// TODO: re-add this when we introduce Testnet2
|
||||
/*
|
||||
@Override
|
||||
public boolean allowMinDifficultyBlocks() {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String getPaymentProtocolId() {
|
||||
// TODO: CHANGE THIS (comment from Dogecoin)
|
||||
return ID_NMC_MAINNET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTestNet() {
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user