|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using Blockcore.Base.Deployments; |
| 4 | +using Blockcore.Consensus; |
| 5 | +using Blockcore.Consensus.BlockInfo; |
| 6 | +using Blockcore.Consensus.ScriptInfo; |
| 7 | +using Blockcore.Consensus.TransactionInfo; |
| 8 | +using Blockcore.Features.Consensus.Rules.CommonRules; |
| 9 | +using Blockcore.Features.Consensus.Rules.ProvenHeaderRules; |
| 10 | +using Blockcore.Features.Consensus.Rules.UtxosetRules; |
| 11 | +using Blockcore.Features.MemoryPool.Rules; |
| 12 | +using Blockcore.Networks.Impleum.Deployments; |
| 13 | +using Blockcore.Networks.Impleum.Policies; |
| 14 | +using Blockcore.Networks.Impleum.Rules; |
| 15 | +using NBitcoin; |
| 16 | +using NBitcoin.BouncyCastle.Math; |
| 17 | +using NBitcoin.DataEncoders; |
| 18 | + |
| 19 | +namespace Blockcore.Networks.Impleum |
| 20 | +{ |
| 21 | + public class ImpleumMain : Network |
| 22 | + { |
| 23 | + public ImpleumMain() |
| 24 | + { |
| 25 | + this.NetworkType = NetworkType.Mainnet; |
| 26 | + this.DefaultConfigFilename = ImpleumSetup.ConfigFileName; // The default name used for the Impleum configuration file. |
| 27 | + |
| 28 | + this.Name = ImpleumSetup.Main.Name; |
| 29 | + this.CoinTicker = ImpleumSetup.Main.CoinTicker; |
| 30 | + this.Magic = ImpleumSetup.Main.Magic; |
| 31 | + this.RootFolderName = ImpleumSetup.Main.RootFolderName; |
| 32 | + this.DefaultPort = ImpleumSetup.Main.DefaultPort; |
| 33 | + this.DefaultRPCPort = ImpleumSetup.Main.DefaultRPCPort; |
| 34 | + this.DefaultAPIPort = ImpleumSetup.Main.DefaultAPIPort; |
| 35 | + |
| 36 | + this.DefaultMaxOutboundConnections = 16; |
| 37 | + this.DefaultMaxInboundConnections = 109; |
| 38 | + this.MaxTipAge = 2 * 60 * 60; |
| 39 | + this.MinTxFee = 10000; |
| 40 | + this.MaxTxFee = Money.Coins(0.1m); |
| 41 | + this.FallbackFee = 10000; |
| 42 | + this.MinRelayTxFee = 10000; |
| 43 | + this.MaxTimeOffsetSeconds = 25 * 60; |
| 44 | + this.DefaultBanTimeSeconds = 11250; // 500 (MaxReorg) * 45 (TargetSpacing) / 2 = 3 hours, 7 minutes and 30 seconds |
| 45 | + |
| 46 | + var consensusFactory = new PosConsensusFactory(); |
| 47 | + |
| 48 | + Block genesisBlock = CreateGenesisBlock(consensusFactory, |
| 49 | + ImpleumSetup.Main.GenesisTime, |
| 50 | + ImpleumSetup.Main.GenesisNonce, |
| 51 | + ImpleumSetup.Main.GenesisBits, |
| 52 | + ImpleumSetup.Main.GenesisVersion, |
| 53 | + ImpleumSetup.Main.GenesisReward, |
| 54 | + ImpleumSetup.GenesisText); |
| 55 | + |
| 56 | + this.Genesis = genesisBlock; |
| 57 | + |
| 58 | + // Taken from StratisX. |
| 59 | + var consensusOptions = new PosConsensusOptions() |
| 60 | + { |
| 61 | + MaxBlockBaseSize = 1_000_000, |
| 62 | + MaxStandardVersion = 2, |
| 63 | + MaxStandardTxWeight = 100_000, |
| 64 | + MaxBlockSigopsCost = 20_000, |
| 65 | + MaxStandardTxSigopsCost = 20_000 / 5, |
| 66 | + WitnessScaleFactor = 4 |
| 67 | + }; |
| 68 | + |
| 69 | + var buriedDeployments = new BuriedDeploymentsArray |
| 70 | + { |
| 71 | + [BuriedDeployments.BIP34] = 0, |
| 72 | + [BuriedDeployments.BIP65] = 0, |
| 73 | + [BuriedDeployments.BIP66] = 0 |
| 74 | + }; |
| 75 | + |
| 76 | + var bip9Deployments = new ImpleumBIP9Deployments() |
| 77 | + { |
| 78 | + // Always active. |
| 79 | + [ImpleumBIP9Deployments.CSV] = new BIP9DeploymentsParameters("CSV", 0, BIP9DeploymentsParameters.AlwaysActive, 999999999, BIP9DeploymentsParameters.DefaultMainnetThreshold), |
| 80 | + [ImpleumBIP9Deployments.Segwit] = new BIP9DeploymentsParameters("Segwit", 1, BIP9DeploymentsParameters.AlwaysActive, 999999999, BIP9DeploymentsParameters.DefaultMainnetThreshold), |
| 81 | + [ImpleumBIP9Deployments.ColdStaking] = new BIP9DeploymentsParameters("ColdStaking", 2, BIP9DeploymentsParameters.AlwaysActive, 999999999, BIP9DeploymentsParameters.DefaultMainnetThreshold) |
| 82 | + }; |
| 83 | + |
| 84 | + this.Consensus = new Consensus.Consensus( |
| 85 | + consensusFactory: consensusFactory, |
| 86 | + consensusOptions: consensusOptions, |
| 87 | + coinType: ImpleumSetup.CoinType, |
| 88 | + hashGenesisBlock: genesisBlock.GetHash(), |
| 89 | + subsidyHalvingInterval: 210000, |
| 90 | + majorityEnforceBlockUpgrade: 750, |
| 91 | + majorityRejectBlockOutdated: 950, |
| 92 | + majorityWindow: 1000, |
| 93 | + buriedDeployments: buriedDeployments, |
| 94 | + bip9Deployments: bip9Deployments, |
| 95 | + bip34Hash: null, |
| 96 | + minerConfirmationWindow: 2016, // nPowTargetTimespan / nPowTargetSpacing |
| 97 | + maxReorgLength: 500, |
| 98 | + defaultAssumeValid: null, |
| 99 | + maxMoney: Money.Coins(ImpleumSetup.MaxSupply), |
| 100 | + coinbaseMaturity: 50, |
| 101 | + premineHeight: 2, |
| 102 | + premineReward: Money.Coins(ImpleumSetup.PremineReward), |
| 103 | + proofOfWorkReward: Money.Coins(ImpleumSetup.PoWBlockReward), |
| 104 | + targetTimespan: TimeSpan.FromSeconds(14 * 24 * 60 * 60), // two weeks |
| 105 | + targetSpacing: ImpleumSetup.TargetSpacing, |
| 106 | + powAllowMinDifficultyBlocks: false, |
| 107 | + posNoRetargeting: false, |
| 108 | + powNoRetargeting: false, |
| 109 | + powLimit: new Target(new uint256("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), |
| 110 | + minimumChainWork: null, |
| 111 | + isProofOfStake: true, |
| 112 | + lastPowBlock: ImpleumSetup.Main.LastPowBlock, |
| 113 | + proofOfStakeLimit: new BigInteger(uint256 |
| 114 | + .Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false)), |
| 115 | + proofOfStakeLimitV2: new BigInteger(uint256 |
| 116 | + .Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false)), |
| 117 | + proofOfStakeReward: Money.Coins(ImpleumSetup.PoSBlockReward), |
| 118 | + proofOfStakeTimestampMask: ImpleumSetup.ProofOfStakeTimestampMask |
| 119 | + ) |
| 120 | + { |
| 121 | + PosEmptyCoinbase = ImpleumSetup.IsPoSv3(), |
| 122 | + PosUseTimeFieldInKernalHash = ImpleumSetup.IsPoSv3() |
| 123 | + }; |
| 124 | + |
| 125 | + |
| 126 | + // TODO: Set your Base58Prefixes |
| 127 | + this.Base58Prefixes = new byte[12][]; |
| 128 | + this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS] = new byte[] { (ImpleumSetup.Main.PubKeyAddress) }; |
| 129 | + this.Base58Prefixes[(int)Base58Type.SCRIPT_ADDRESS] = new byte[] { (ImpleumSetup.Main.ScriptAddress) }; |
| 130 | + this.Base58Prefixes[(int)Base58Type.SECRET_KEY] = new byte[] { (ImpleumSetup.Main.SecretAddress) }; |
| 131 | + |
| 132 | + this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_NO_EC] = new byte[] { 0x01, 0x42 }; |
| 133 | + this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_EC] = new byte[] { 0x01, 0x43 }; |
| 134 | + this.Base58Prefixes[(int)Base58Type.EXT_PUBLIC_KEY] = new byte[] { (0x04), (0x88), (0xB2), (0x1E) }; |
| 135 | + this.Base58Prefixes[(int)Base58Type.EXT_SECRET_KEY] = new byte[] { (0x04), (0x88), (0xAD), (0xE4) }; |
| 136 | + this.Base58Prefixes[(int)Base58Type.PASSPHRASE_CODE] = new byte[] { 0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2 }; |
| 137 | + this.Base58Prefixes[(int)Base58Type.CONFIRMATION_CODE] = new byte[] { 0x64, 0x3B, 0xF6, 0xA8, 0x9A }; |
| 138 | + this.Base58Prefixes[(int)Base58Type.ASSET_ID] = new byte[] { 23 }; |
| 139 | + |
| 140 | + this.Bech32Encoders = new Bech32Encoder[2]; |
| 141 | + var encoder = new Bech32Encoder(ImpleumSetup.Main.CoinTicker.ToLowerInvariant()); |
| 142 | + this.Bech32Encoders[(int)Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder; |
| 143 | + this.Bech32Encoders[(int)Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder; |
| 144 | + |
| 145 | + this.Checkpoints = ImpleumSetup.Main.Checkpoints; |
| 146 | + this.DNSSeeds = ImpleumSetup.Main.DNS; |
| 147 | + this.SeedNodes = ImpleumSetup.Main.Nodes; |
| 148 | + |
| 149 | + this.StandardScriptsRegistry = new ImpleumStandardScriptsRegistry(); |
| 150 | + |
| 151 | + // 64 below should be changed to TargetSpacingSeconds when we move that field. |
| 152 | + Assert(this.DefaultBanTimeSeconds <= this.Consensus.MaxReorgLength * 64 / 2); |
| 153 | + |
| 154 | + Assert(this.Consensus.HashGenesisBlock == uint256.Parse(ImpleumSetup.Main.HashGenesisBlock)); |
| 155 | + Assert(this.Genesis.Header.HashMerkleRoot == uint256.Parse(ImpleumSetup.Main.HashMerkleRoot)); |
| 156 | + |
| 157 | + RegisterRules(this.Consensus); |
| 158 | + RegisterMempoolRules(this.Consensus); |
| 159 | + } |
| 160 | + |
| 161 | + protected void RegisterRules(IConsensus consensus) |
| 162 | + { |
| 163 | + consensus.ConsensusRules |
| 164 | + .Register<HeaderTimeChecksRule>() |
| 165 | + .Register<HeaderTimeChecksPosRule>() |
| 166 | + .Register<PosFutureDriftRule>() |
| 167 | + .Register<CheckDifficultyPosRule>() |
| 168 | + .Register<ImpleumHeaderVersionRule>() |
| 169 | + .Register<ProvenHeaderSizeRule>() |
| 170 | + .Register<ProvenHeaderCoinstakeRule>(); |
| 171 | + |
| 172 | + consensus.ConsensusRules |
| 173 | + .Register<BlockMerkleRootRule>() |
| 174 | + .Register<PosBlockSignatureRepresentationRule>() |
| 175 | + .Register<PosBlockSignatureRule>(); |
| 176 | + |
| 177 | + consensus.ConsensusRules |
| 178 | + .Register<SetActivationDeploymentsPartialValidationRule>() |
| 179 | + .Register<PosTimeMaskRule>() |
| 180 | + |
| 181 | + // rules that are inside the method ContextualCheckBlock |
| 182 | + .Register<TransactionLocktimeActivationRule>() |
| 183 | + .Register<CoinbaseHeightActivationRule>() |
| 184 | + .Register<WitnessCommitmentsRule>() |
| 185 | + .Register<BlockSizeRule>() |
| 186 | + |
| 187 | + // rules that are inside the method CheckBlock |
| 188 | + .Register<EnsureCoinbaseRule>() |
| 189 | + .Register<CheckPowTransactionRule>() |
| 190 | + .Register<CheckPosTransactionRule>() |
| 191 | + .Register<CheckSigOpsRule>() |
| 192 | + .Register<PosCoinstakeRule>(); |
| 193 | + |
| 194 | + consensus.ConsensusRules |
| 195 | + .Register<SetActivationDeploymentsFullValidationRule>() |
| 196 | + |
| 197 | + .Register<CheckDifficultyHybridRule>() |
| 198 | + |
| 199 | + // rules that require the store to be loaded (coinview) |
| 200 | + .Register<FetchUtxosetRule>() |
| 201 | + .Register<TransactionDuplicationActivationRule>() |
| 202 | + .Register<CheckPosUtxosetRule>() // implements BIP68, MaxSigOps and BlockReward calculation |
| 203 | + // Place the PosColdStakingRule after the PosCoinviewRule to ensure that all input scripts have been evaluated |
| 204 | + // and that the "IsColdCoinStake" flag would have been set by the OP_CHECKCOLDSTAKEVERIFY opcode if applicable. |
| 205 | + .Register<PosColdStakingRule>() |
| 206 | + .Register<PushUtxosetRule>() |
| 207 | + .Register<FlushUtxosetRule>(); |
| 208 | + } |
| 209 | + |
| 210 | + protected void RegisterMempoolRules(IConsensus consensus) |
| 211 | + { |
| 212 | + consensus.MempoolRules = new List<Type>() |
| 213 | + { |
| 214 | + typeof(CheckConflictsMempoolRule), |
| 215 | + typeof(CheckCoinViewMempoolRule), |
| 216 | + typeof(CreateMempoolEntryMempoolRule), |
| 217 | + typeof(CheckSigOpsMempoolRule), |
| 218 | + typeof(CheckFeeMempoolRule), |
| 219 | + typeof(CheckRateLimitMempoolRule), |
| 220 | + typeof(CheckAncestorsMempoolRule), |
| 221 | + typeof(CheckReplacementMempoolRule), |
| 222 | + typeof(CheckAllInputsMempoolRule), |
| 223 | + typeof(CheckTxOutDustRule) |
| 224 | + }; |
| 225 | + } |
| 226 | + |
| 227 | + protected static Block CreateGenesisBlock(ConsensusFactory consensusFactory, uint nTime, uint nNonce, uint nBits, int nVersion, Money genesisReward, string genesisText) |
| 228 | + { |
| 229 | + Transaction txNew = consensusFactory.CreateTransaction(); |
| 230 | + txNew.Version = 1; |
| 231 | + |
| 232 | + if (txNew is IPosTransactionWithTime posTx) |
| 233 | + { |
| 234 | + posTx.Time = nTime; |
| 235 | + } |
| 236 | + |
| 237 | + txNew.AddInput(new TxIn() |
| 238 | + { |
| 239 | + ScriptSig = new Script(Op.GetPushOp(0), new Op() |
| 240 | + { |
| 241 | + Code = (OpcodeType)0x1, |
| 242 | + PushData = new[] { (byte)42 } |
| 243 | + }, Op.GetPushOp(Encoders.ASCII.DecodeData(genesisText))) |
| 244 | + }); |
| 245 | + |
| 246 | + txNew.AddOutput(new TxOut() |
| 247 | + { |
| 248 | + Value = genesisReward, |
| 249 | + }); |
| 250 | + |
| 251 | + Block genesis = consensusFactory.CreateBlock(); |
| 252 | + genesis.Header.BlockTime = Utils.UnixTimeToDateTime(nTime); |
| 253 | + genesis.Header.Bits = nBits; |
| 254 | + genesis.Header.Nonce = nNonce; |
| 255 | + genesis.Header.Version = nVersion; |
| 256 | + genesis.Transactions.Add(txNew); |
| 257 | + genesis.Header.HashPrevBlock = uint256.Zero; |
| 258 | + genesis.UpdateMerkleRoot(); |
| 259 | + |
| 260 | + return genesis; |
| 261 | + } |
| 262 | + } |
| 263 | +} |
0 commit comments