text: // Copyright (c) 2010 Satoshi Nakamoto
  // Copyright (c) 2009-2014 The Bitcoin developers
  // Copyright (c) 2014-2015 The Dash developers
  // Copyright (c) 2015-2017 The PIVX developers
  // Copyright (c) 2017-2019 The ICC Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #include "chainparams.h"
  
  #include "random.h"
  #include "util.h"
  #include "utilstrencodings.h"
  
  #include <assert.h>
  
  #include <boost/assign/list_of.hpp>
  
  using namespace std;
  using namespace boost::assign;
  
  struct SeedSpec6 {
      uint8_t addr[16];
      uint16_t port;
  };
  
  #include "chainparamsseeds.h"
  
  /**
   * Main network
   */
  
  
  static void convertSeed6(std::vector<CAddress>& vSeedsOut, const SeedSpec6* data, unsigned int count)
  {
      const int64_t nOneWeek = 7 * 24 * 60 * 60;
      for (unsigned int i = 0; i < count; i++) {
          struct in6_addr ip;
          memcpy(&ip, data[i].addr, sizeof(ip));
          CAddress addr(CService(ip, data[i].port));
          addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek;
          vSeedsOut.push_back(addr);
      }
  }
  
  static Checkpoints::MapCheckpoints mapCheckpoints =
      boost::assign::map_list_of
      (0, uint256("0x00000a6fe0f3ccd07ee3eadc9ea83bfa50a39a0013af3190c76c5eb73ac5cb8e"));
  
  
  
  static const Checkpoints::CCheckpointData data = {
      &mapCheckpoints,
      1560000557, // * UNIX timestamp of last checkpoint block
      0,        // * total number of transactions between genesis and last checkpoint
                //   (the tx=... number in the SetBestChain debug.log lines)
      2000      // * estimated number of transactions per day after checkpoint
  };
  
  static Checkpoints::MapCheckpoints mapCheckpointsTestnet =
      boost::assign::map_list_of(0, uint256("0x0000092557a096fcaadf38bb9852efa4301f8ea455d278f8f14e621eea465175"));
  static const Checkpoints::CCheckpointData dataTestnet = {
      &mapCheckpointsTestnet,
      1552631354,
      0,
      250};
  
  static Checkpoints::MapCheckpoints mapCheckpointsRegtest =
      boost::assign::map_list_of(0, uint256("0x4dddfc2b0ad9549aff6fedebc182f1b73aa739776e7ae796e5578c677a5c07e9"));
  static const Checkpoints::CCheckpointData dataRegtest = {
      &mapCheckpointsRegtest,
      1555496977,
      0,
      100};
  
  class CMainParams : public CChainParams
  {
  public:
      CMainParams()
      {
          networkID = CBaseChainParams::MAIN;
          strNetworkID = "main";
          pchMessageStart[0] = 0x3a;
          pchMessageStart[1] = 0x3f;
          pchMessageStart[2] = 0x33;
          pchMessageStart[3] = 0x19;
          vAlertPubKey = ParseHex("040a1ade1eed7451e9d8f45193bc3d00d6039d955215af9671d311a9097bfc2d83f2df32d49b920511bf912f3f13da36c481359acec29944d3965c26da1fe2f6eb");
          nDefaultPort = 50578;
          bnProofOfWorkLimit = ~uint256(0) >> 20; // ICC starting difficulty is 1 / 2^12
          nSubsidyHalvingInterval = 210000;       // one year
          nMaxReorganizationDepth = 100;
          nEnforceBlockUpgradeMajority = 750;
          nRejectBlockOutdatedMajority = 950;
          nToCheckBlockUpgradeMajority = 1000;
          nMinerThreads = 0;
          nTargetTimespan = 1 * 60; // ICC: every block
          nTargetSpacing = 2 * 60;  // ICC: 1 minute
          nLastPOWBlock = 100;
          nMaturity = 20;
          nMasternodeCountDrift = 20;
          nModifierUpdateBlock = 1;
          nMaxMoneyOut = 5000000 * COIN;
          nMasternodeCollateral = 1000;
  
          const char* pszTimestamp = "This is genesis block for Internet Cafe Coin";
          CMutableTransaction txNew;
          txNew.vin.resize(1);
          txNew.vout.resize(1);
          txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
          txNew.vout[0].nValue = 50 * COIN;
          txNew.vout[0].scriptPubKey = CScript() << ParseHex("0440d70a9a67c1f373523418125884975d38ff37d7d099d27ff1304dd92aa1d246a28e3f735ac9b9dcfa13212ac4a0c3593664930cfbf41a3eecfc0f04347a1d44") << OP_CHECKSIG;
          genesis.vtx.push_back(txNew);
          genesis.hashPrevBlock = 0;
          genesis.hashMerkleRoot = genesis.BuildMerkleTree();
          genesis.nVersion = 1;
          genesis.nTime = 1560000557;                      
          genesis.nBits = 0x1e0ffff0;
          genesis.nNonce = 23238178;
  
          hashGenesisBlock = genesis.GetHash();
          assert(hashGenesisBlock == uint256("0x00000a6fe0f3ccd07ee3eadc9ea83bfa50a39a0013af3190c76c5eb73ac5cb8e"));
          assert(genesis.hashMerkleRoot == uint256("0xa97591018fd76fafdac7f220b11ec5c882cc1cc9d823cee74731f8bf658f3ba7"));
  
          vSeeds.push_back(CDNSSeedData("seed1.internetcafecoin.com", "seed1.internetcafecoin.com"));
          vSeeds.push_back(CDNSSeedData("seed2.internetcafecoin.com", "seed2.internetcafecoin.com"));
          vSeeds.push_back(CDNSSeedData("seed3.internetcafecoin.com", "seed3.internetcafecoin.com"));
  
          base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 28);
          base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 13);
          base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 212);
          // ICC BIP32 pubkeys start with 'xpub' (Bitcoin defaults)
          base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x02)(0x2F)(0x25)(0x43).convert_to_container<std::vector<unsigned char> >();
          // ICC BIP32 pubkeys start with 'xprv' (Bitcoin defaults)
          base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x02)(0x22)(0x31)(0x2C).convert_to_container<std::vector<unsigned char> >();
          // 	BIP44 coin type is '0X80000a00' from https://github.com/satoshilabs/slips/blob/master/slip-0044.md
          base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x08)(0x57).convert_to_container<std::vector<unsigned char> >();
  
          convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main));
  
          fRequireRPCPassword = true;
          fMiningRequiresPeers = true;
          fAllowMinDifficultyBlocks = false;
          fDefaultConsistencyChecks = false;
          fRequireStandard = true;
          fMineBlocksOnDemand = false;
          fSkipProofOfWorkCheck = false;
          fTestnetToBeDeprecatedFieldRPC = false;
          fHeadersFirstSyncingActive = false;
  
          nPoolMaxTransactions = 3;
          strSporkKey = "0405312725aa5e9252f7041eb78a1ff56e87049df1c1712eb190df7164c439859561e8769021f54be068813c1670fca95dcf188bb00bece6b03d89e94c481ae0fd";
          strPrivatesendPoolDummyAddress = "CZs9whRed9jPjtCzRKx3hKrSbEps6Ev28X";
          nStartMasternodePayments = 1556485990;
      }
  
      const Checkpoints::CCheckpointData& Checkpoints() const
      {
          return data;
      }
  };
  static CMainParams mainParams;
  
  /**
   * Testnet (v3)
   */
  class CTestNetParams : public CMainParams
  {
  public:
      CTestNetParams()
      {
          networkID = CBaseChainParams::TESTNET;
          strNetworkID = "test";
          pchMessageStart[0] = 0x65;
          pchMessageStart[1] = 0x4c;
          pchMessageStart[2] = 0x67;
          pchMessageStart[3] = 0xc4;
          vAlertPubKey = ParseHex("048fc0881c5e21ef9205c5f605635e8274bb1ca53607983885d228ab02e9cc93822c20113556d432ed5041e52ad6d2c50693bf717790cb55a8606ad38bab6105f6");
          nDefaultPort = 55578;
          nEnforceBlockUpgradeMajority = 51;
          nRejectBlockOutdatedMajority = 75;
          nToCheckBlockUpgradeMajority = 100;
          nMinerThreads = 0;
          nTargetTimespan = 1 * 60; // ICC: 1 day
          nTargetSpacing = 1 * 60;  // ICC: 1 minute
          nLastPOWBlock = 200;
          nMaturity = 10;
          nMasternodeCountDrift = 4;
          nModifierUpdateBlock = 1; //approx Mon, 17 Apr 2017 04:00:00 GMT
          nMaxMoneyOut = 100000000 * COIN;
  
          //! Modify the testnet genesis block so the timestamp is valid for a later start.
          genesis.nTime = 1552631354;
          genesis.nNonce = 18732581;
  
          hashGenesisBlock = genesis.GetHash();
          assert(hashGenesisBlock == uint256("0x0000092557a096fcaadf38bb9852efa4301f8ea455d278f8f14e621eea465175"));
  
          vFixedSeeds.clear();
          vSeeds.clear();
          vSeeds.push_back(CDNSSeedData("testseed1.internetcafecoin.com", "testseed1.internetcafecoin.com"));
  
          base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 90); // Testnet icc addresses start with 'x' or 'y'
          base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 19); // Testnet icc script addresses start with '8' or '9'
          base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 240);    // Testnet private keys start with '9' or 'c' (Bitcoin defaults)
                                                                              // ICC BIP32 pubkeys start with 'xpub' (Bitcoin defaults)
          base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x3a)(0x80)(0x61)(0xa0).convert_to_container<std::vector<unsigned char> >();
          // ICC BIP32 pubkeys start with 'xprv' (Bitcoin defaults)
          base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x3a)(0x80)(0x58)(0x37).convert_to_container<std::vector<unsigned char> >();
          // Testnet icc BIP44 coin type is '1' (All coin's testnet default)
          base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container<std::vector<unsigned char> >();
  
          convertSeed6(vFixedSeeds, pnSeed6_test, ARRAYLEN(pnSeed6_test));
  
          fRequireRPCPassword = true;
          fMiningRequiresPeers = true;
          fAllowMinDifficultyBlocks = true;
          fDefaultConsistencyChecks = false;
          fRequireStandard = true;
          fMineBlocksOnDemand = false;
          fTestnetToBeDeprecatedFieldRPC = true;
  
          nPoolMaxTransactions = 2;
          strSporkKey = "040b2a8e97a42ee678ee46b302324a2bfaf268cb034f58c9dae4728d6638890ab89c11f0e270a752e6d998ca2954102e40838e78f1ba246feeae7d838fd27a7432";
          strPrivatesendPoolDummyAddress = "dW3yd6puxNBA1JWtVJkubBetj793NTw2mp";
          nStartMasternodePayments = 1562531573;
      }
      const Checkpoints::CCheckpointData& Checkpoints() const
      {
          return dataTestnet;
      }
  };
  static CTestNetParams testNetParams;
  
  /**
   * Regression test
   */
  class CRegTestParams : public CTestNetParams
  {
  public:
      CRegTestParams()
      {
          networkID = CBaseChainParams::REGTEST;
          strNetworkID = "regtest";
          pchMessageStart[0] = 0x25;
          pchMessageStart[1] = 0xcf;
          pchMessageStart[2] = 0x9a;
          pchMessageStart[3] = 0x41;
          nSubsidyHalvingInterval = 150;
          nEnforceBlockUpgradeMajority = 750;
          nRejectBlockOutdatedMajority = 950;
          nToCheckBlockUpgradeMajority = 1000;
          nMinerThreads = 1;
          nTargetTimespan = 24 * 60 * 60; // ICC: 1 day
          nTargetSpacing = 1 * 60;        // ICC: 1 minutes
          bnProofOfWorkLimit = ~uint256(0) >> 1;
          genesis.nTime = 1555496977;
          genesis.nBits = 0x207fffff;
          genesis.nNonce = 440281;
  
          hashGenesisBlock = genesis.GetHash();
          nDefaultPort = 43445;
          assert(hashGenesisBlock == uint256("0x4dddfc2b0ad9549aff6fedebc182f1b73aa739776e7ae796e5578c677a5c07e9"));
  
          vFixedSeeds.clear(); //! Testnet mode doesn't have any fixed seeds.
          vSeeds.clear();      //! Testnet mode doesn't have any DNS seeds.
  
          fRequireRPCPassword = false;
          fMiningRequiresPeers = false;
          fAllowMinDifficultyBlocks = true;
          fDefaultConsistencyChecks = true;
          fRequireStandard = true;
          fMineBlocksOnDemand = false;
          fTestnetToBeDeprecatedFieldRPC = false;
      }
      const Checkpoints::CCheckpointData& Checkpoints() const
      {
          return dataRegtest;
      }
  };
  static CRegTestParams regTestParams;
  
  /**
   * Unit test
   */
  class CUnitTestParams : public CMainParams, public CModifiableParams
  {
  public:
      CUnitTestParams()
      {
          networkID = CBaseChainParams::UNITTEST;
          strNetworkID = "unittest";
          nDefaultPort = 53578;
          vFixedSeeds.clear(); //! Unit test mode doesn't have any fixed seeds.
          vSeeds.clear();      //! Unit test mode doesn't have any DNS seeds.
  
          fRequireRPCPassword = false;
          fMiningRequiresPeers = false;
          fDefaultConsistencyChecks = true;
          fAllowMinDifficultyBlocks = false;
          fMineBlocksOnDemand = true;
      }
  
      const Checkpoints::CCheckpointData& Checkpoints() const
      {
          // UnitTest share the same checkpoints as MAIN
          return data;
      }
  
      //! Published setters to allow changing values in unit test cases
      virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval = anSubsidyHalvingInterval; }
      virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority = anEnforceBlockUpgradeMajority; }
      virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority = anRejectBlockOutdatedMajority; }
      virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority = anToCheckBlockUpgradeMajority; }
      virtual void setDefaultConsistencyChecks(bool afDefaultConsistencyChecks) { fDefaultConsistencyChecks = afDefaultConsistencyChecks; }
      virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks = afAllowMinDifficultyBlocks; }
      virtual void setSkipProofOfWorkCheck(bool afSkipProofOfWorkCheck) { fSkipProofOfWorkCheck = afSkipProofOfWorkCheck; }
  };
  static CUnitTestParams unitTestParams;
  
  
  static CChainParams* pCurrentParams = 0;
  
  CModifiableParams* ModifiableParams()
  {
      assert(pCurrentParams);
      assert(pCurrentParams == &unitTestParams);
      return (CModifiableParams*)&unitTestParams;
  }
  
  const CChainParams& Params()
  {
      assert(pCurrentParams);
      return *pCurrentParams;
  }
  
  CChainParams& Params(CBaseChainParams::Network network)
  {
      switch (network) {
      case CBaseChainParams::MAIN:
          return mainParams;
      case CBaseChainParams::TESTNET:
          return testNetParams;
      case CBaseChainParams::REGTEST:
          return regTestParams;
      case CBaseChainParams::UNITTEST:
          return unitTestParams;
      default:
          assert(false && "Unimplemented network");
          return mainParams;
      }
  }
  
  void SelectParams(CBaseChainParams::Network network)
  {
      SelectBaseParams(network);
      pCurrentParams = &Params(network);
  }
  
  bool SelectParamsFromCommandLine()
  {
      CBaseChainParams::Network network = NetworkIdFromCommandLine();
      if (network == CBaseChainParams::MAX_NETWORK_TYPES)
          return false;
  
      SelectParams(network);
      return true;
  }
  