private static Block createGenesis(NetworkParameters n) {
   Block genesisBlock = new Block(n);
   Transaction t = new Transaction(n);
   try {
     // A script containing the difficulty bits and the following message:
     //
     //   "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
     byte[] bytes =
         Utils.HEX.decode(
             "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
     t.addInput(new TransactionInput(n, t, bytes));
     ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
     Script.writeBytes(
         scriptPubKeyBytes,
         Utils.HEX.decode(
             "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
     scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
     t.addOutput(new TransactionOutput(n, t, FIFTY_COINS, scriptPubKeyBytes.toByteArray()));
   } catch (Exception e) {
     // Cannot happen.
     throw new RuntimeException(e);
   }
   genesisBlock.addTransaction(t);
   return genesisBlock;
 }
/**
 * NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.
 *
 * <p>This is an abstract class, concrete instantiations can be found in the params package. There
 * are four: one for the main network ({@link MainNetParams}), one for the public test network, and
 * two others that are intended for unit testing and local app development purposes. Although this
 * class contains some aliases for them, you are encouraged to call the static get() methods on each
 * specific params class directly.
 */
public abstract class NetworkParameters implements Serializable {
  /** The protocol version this library implements. */
  public static final int PROTOCOL_VERSION = 70001;

  /**
   * The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few
   * others.
   */
  public static final byte[] SATOSHI_KEY =
      Utils.HEX.decode(
          "04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");

  /** The string returned by getId() for the main, production network where people trade things. */
  public static final String ID_MAINNET = "org.bitcoin.production";
  /** The string returned by getId() for the testnet. */
  public static final String ID_TESTNET = "org.bitcoin.test";
  /** The string returned by getId() for regtest mode. */
  public static final String ID_REGTEST = "org.bitcoin.regtest";
  /** Unit test network. */
  public static final String ID_UNITTESTNET = "org.bitcoinj.unittest";

  /** The string used by the payment protocol to represent the main net. */
  public static final String PAYMENT_PROTOCOL_ID_MAINNET = "main";
  /** The string used by the payment protocol to represent the test net. */
  public static final String PAYMENT_PROTOCOL_ID_TESTNET = "test";

  // TODO: Seed nodes should be here as well.

  protected Block genesisBlock;
  protected BigInteger maxTarget;
  protected int port;
  protected long
      packetMagic; // Indicates message origin network and is used to seek to the next message when
                   // stream state is unknown.
  protected int addressHeader;
  protected int p2shHeader;
  protected int dumpedPrivateKeyHeader;
  protected int interval;
  protected int targetTimespan;
  protected byte[] alertSigningKey;
  protected int bip32HeaderPub;
  protected int bip32HeaderPriv;

  /**
   * See getId(). This may be null for old deserialized wallets. In that case we derive it
   * heuristically by looking at the port number.
   */
  protected String id;

  /** The depth of blocks required for a coinbase transaction to be spendable. */
  protected int spendableCoinbaseDepth;

  protected int subsidyDecreaseBlockCount;

  protected int[] acceptableAddressCodes;
  protected String[] dnsSeeds;
  protected Map<Integer, Sha256Hash> checkpoints = new HashMap<Integer, Sha256Hash>();

  protected NetworkParameters() {
    alertSigningKey = SATOSHI_KEY;
    genesisBlock = createGenesis(this);
  }

  private static Block createGenesis(NetworkParameters n) {
    Block genesisBlock = new Block(n);
    Transaction t = new Transaction(n);
    try {
      // A script containing the difficulty bits and the following message:
      //
      //   "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
      byte[] bytes =
          Utils.HEX.decode(
              "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
      t.addInput(new TransactionInput(n, t, bytes));
      ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
      Script.writeBytes(
          scriptPubKeyBytes,
          Utils.HEX.decode(
              "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
      scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
      t.addOutput(new TransactionOutput(n, t, FIFTY_COINS, scriptPubKeyBytes.toByteArray()));
    } catch (Exception e) {
      // Cannot happen.
      throw new RuntimeException(e);
    }
    genesisBlock.addTransaction(t);
    return genesisBlock;
  }

  public static final int TARGET_TIMESPAN =
      14 * 24 * 60 * 60; // 2 weeks per difficulty cycle, on average.
  public static final int TARGET_SPACING = 10 * 60; // 10 minutes per block.
  public static final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;

  /**
   * Blocks with a timestamp after this should enforce BIP 16, aka "Pay to script hash". This BIP
   * changed the network rules in a soft-forking manner, that is, blocks that don't follow the rules
   * are accepted but not mined upon and thus will be quickly re-orged out as long as the majority
   * are enforcing the rule.
   */
  public static final int BIP16_ENFORCE_TIME = 1333238400;

  /** The maximum number of coins to be generated */
  public static final long MAX_COINS = 21000000;

  /** The maximum money to be generated */
  public static final Coin MAX_MONEY = COIN.multiply(MAX_COINS);

  /** Alias for TestNet3Params.get(), use that instead. */
  @Deprecated
  public static NetworkParameters testNet() {
    return TestNet3Params.get();
  }

  /** Alias for TestNet2Params.get(), use that instead. */
  @Deprecated
  public static NetworkParameters testNet2() {
    return TestNet2Params.get();
  }

  /** Alias for TestNet3Params.get(), use that instead. */
  @Deprecated
  public static NetworkParameters testNet3() {
    return TestNet3Params.get();
  }

  /** Alias for MainNetParams.get(), use that instead */
  @Deprecated
  public static NetworkParameters prodNet() {
    return MainNetParams.get();
  }

  /** Returns a testnet params modified to allow any difficulty target. */
  @Deprecated
  public static NetworkParameters unitTests() {
    return UnitTestParams.get();
  }

  /** Returns a standard regression test params (similar to unitTests) */
  @Deprecated
  public static NetworkParameters regTests() {
    return RegTestParams.get();
  }

  /** A Java package style string acting as unique ID for these parameters */
  public String getId() {
    return id;
  }

  public abstract String getPaymentProtocolId();

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    NetworkParameters other = (NetworkParameters) o;
    return getId().equals(other.getId());
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(getId());
  }

  /** Returns the network parameters for the given string ID or NULL if not recognized. */
  @Nullable
  public static NetworkParameters fromID(String id) {
    if (id.equals(ID_MAINNET)) {
      return MainNetParams.get();
    } else if (id.equals(ID_TESTNET)) {
      return TestNet3Params.get();
    } else if (id.equals(ID_UNITTESTNET)) {
      return UnitTestParams.get();
    } else if (id.equals(ID_REGTEST)) {
      return RegTestParams.get();
    } else {
      return null;
    }
  }

  /**
   * Returns the network parameters for the given string paymentProtocolID or NULL if not
   * recognized.
   */
  @Nullable
  public static NetworkParameters fromPmtProtocolID(String pmtProtocolId) {
    if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_MAINNET)) {
      return MainNetParams.get();
    } else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_TESTNET)) {
      return TestNet3Params.get();
    } else {
      return null;
    }
  }

  public int getSpendableCoinbaseDepth() {
    return spendableCoinbaseDepth;
  }

  /**
   * Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash
   * matches.
   */
  public boolean passesCheckpoint(int height, Sha256Hash hash) {
    Sha256Hash checkpointHash = checkpoints.get(height);
    return checkpointHash == null || checkpointHash.equals(hash);
  }

  /** Returns true if the given height has a recorded checkpoint. */
  public boolean isCheckpoint(int height) {
    Sha256Hash checkpointHash = checkpoints.get(height);
    return checkpointHash != null;
  }

  public int getSubsidyDecreaseBlockCount() {
    return subsidyDecreaseBlockCount;
  }

  /** Returns DNS names that when resolved, give IP addresses of active peers. */
  public String[] getDnsSeeds() {
    return dnsSeeds;
  }

  /**
   * Genesis block for this chain.
   *
   * <p>The first block in every chain is a well known constant shared between all Bitcoin
   * implemenetations. For a block to be valid, it must be eventually possible to work backwards to
   * the genesis block by following the prevBlockHash pointers in the block headers.
   *
   * <p>The genesis blocks for both test and main networks contain the timestamp of when they were
   * created, and a message in the coinbase transaction. It says, <i>"The Times 03/Jan/2009
   * Chancellor on brink of second bailout for banks"</i>.
   */
  public Block getGenesisBlock() {
    return genesisBlock;
  }

  /** Default TCP port on which to connect to nodes. */
  public int getPort() {
    return port;
  }

  /** The header bytes that identify the start of a packet on this network. */
  public long getPacketMagic() {
    return packetMagic;
  }

  /**
   * First byte of a base58 encoded address. See {@link org.bitcoinj.core.Address}. This is the same
   * as acceptableAddressCodes[0] and is the one used for "normal" addresses. Other types of address
   * may be encountered with version codes found in the acceptableAddressCodes array.
   */
  public int getAddressHeader() {
    return addressHeader;
  }

  /** First byte of a base58 encoded P2SH address. P2SH addresses are defined as part of BIP0013. */
  public int getP2SHHeader() {
    return p2shHeader;
  }

  /**
   * First byte of a base58 encoded dumped private key. See {@link
   * org.bitcoinj.core.DumpedPrivateKey}.
   */
  public int getDumpedPrivateKeyHeader() {
    return dumpedPrivateKeyHeader;
  }

  /**
   * How much time in seconds is supposed to pass between "interval" blocks. If the actual elapsed
   * time is significantly different from this value, the network difficulty formula will produce a
   * different value. Both test and main Bitcoin networks use 2 weeks (1209600 seconds).
   */
  public int getTargetTimespan() {
    return targetTimespan;
  }

  /**
   * The version codes that prefix addresses which are acceptable on this network. Although Satoshi
   * intended these to be used for "versioning", in fact they are today used to discriminate what
   * kind of data is contained in the address and to prevent accidentally sending coins across
   * chains which would destroy them.
   */
  public int[] getAcceptableAddressCodes() {
    return acceptableAddressCodes;
  }

  /**
   * If we are running in testnet-in-a-box mode, we allow connections to nodes with 0 non-genesis
   * blocks.
   */
  public boolean allowEmptyPeerChain() {
    return true;
  }

  /**
   * How many blocks pass between difficulty adjustment periods. Bitcoin standardises this to be
   * 2015.
   */
  public int getInterval() {
    return interval;
  }

  /** Maximum target represents the easiest allowable proof of work. */
  public BigInteger getMaxTarget() {
    return maxTarget;
  }

  /**
   * The key used to sign {@link org.bitcoinj.core.AlertMessage}s. You can use {@link
   * org.bitcoinj.core.ECKey#verify(byte[], byte[], byte[])} to verify signatures using it.
   */
  public byte[] getAlertSigningKey() {
    return alertSigningKey;
  }

  /** Returns the 4 byte header for BIP32 (HD) wallet - public key part. */
  public int getBip32HeaderPub() {
    return bip32HeaderPub;
  }

  /** Returns the 4 byte header for BIP32 (HD) wallet - private key part. */
  public int getBip32HeaderPriv() {
    return bip32HeaderPriv;
  }
}