// transactions need to be already sorted private Block(long ledgerHeight, SortedList <TransactionHash, SignedTransaction> transactions, short?index) { LedgerHeight = ledgerHeight; FeeTransactionIndex = index; Transactions = transactions.Values.ToList(); // TODO fee transaction index? // TODO LedgerHeight? merkleRoot = MerkleNode <TransactionHash> .GetRoot(Transactions.Select(t => t.Hash)); Hash = new BlockHash(merkleRoot.Hash.Bytes); }
private LedgerMerkleRoot(SortedList <AccountHash, Account> accounts, SortedList <TxDeclarationHash, TxDeclaration> declarations, ILogger logger) { // TODO logger here looks ugly this.logger = logger; this.accounts = MerkleNode <AccountHash> .GetRoot(accounts.Keys); this.declarations = MerkleNode <TxDeclarationHash> .GetRoot(declarations.Keys); Hash = GetHash(); #if DEBUG DumpTree(accounts, declarations); #endif }
public ViewResult MAST(MASTModel model) { try { var script = new Script(Sanitize(model.Script)); model.DecomposedScripts = new List <DecomposedScript>(); var subScripts = script.Decompose(); var hashes = subScripts.Select(s => Hashes.Hash256(s.ToBytes())).ToArray(); model.MerkleRoot = MerkleNode.GetRoot(hashes).Hash; int fullScriptSize = script.ToBytes().Length; model.FullScriptSize = fullScriptSize; int i = 0; foreach (var subScript in subScripts) { bool[] matches = new bool[hashes.Length]; matches[i] = true; PartialMerkleTree partial = new PartialMerkleTree(hashes, matches); DecomposedScript s = new DecomposedScript(); s.Script = subScript.ToString(); s.Bytes = Encoders.Hex.EncodeData(subScript.ToBytes()); s.Hash = Hashes.Hash256(subScript.ToBytes()); s.PartialMerkleTree = Encoders.Hex.EncodeData(partial.ToBytes()); model.DecomposedScripts.Add(s); s.Size = subScript.ToBytes().Length + partial.ToBytes().Length; s.Saving = (int)(((decimal)(fullScriptSize - s.Size) / fullScriptSize) * 100m); s.Size160 = (int)(subScript.ToBytes().Length + (decimal)partial.ToBytes().Length * 0.625m); s.Saving160 = (int)(((decimal)(fullScriptSize - s.Size160) / fullScriptSize) * 100m); i++; } } catch (FormatException ex) { ModelState.AddModelError("Script", "Invalid script (" + ex.Message + ")"); return(View(model)); } return(View(model)); }
public override void Init(EquihashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, Network network, EquihashSolver solver) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.clock = clock; this.poolAddressDestination = poolAddressDestination; coin = poolConfig.Template.As <EquihashCoinTemplate>(); this.network = network; var equihashTemplate = poolConfig.Template.As <EquihashCoinTemplate>(); networkParams = coin.GetNetwork(network.ChainName); BlockTemplate = blockTemplate; JobId = jobId; Difficulty = (double)new BigRational(networkParams.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); this.solver = solver; if (!string.IsNullOrEmpty(BlockTemplate.Target)) { blockTargetValue = new uint256(BlockTemplate.Target); } else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseInPlace() .ToHexString(); BuildCoinbase(); // build tx hashes var txHashes = new List <uint256> { new(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.TxId.HexToReverseByteArray()))); // build merkle root merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseInPlace(); merkleRootReversed = merkleRoot.ReverseInPlace(); merkleRootReversedHex = merkleRootReversed.ToHexString(); jobParams = new object[] { JobId, BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), previousBlockHashReversedHex, merkleRootReversedHex, BlockTemplate.Height.ReverseByteOrder().ToStringHex8() + sha256Empty.Take(28).ToHexString(), // height + hashReserved BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), BlockTemplate.Bits.HexToReverseByteArray().ToHexString(), false }; } }
public override void Init(ZCashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, BitcoinNetworkType networkType, bool isPoS, double shareMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.RequiresNonNull(coinbaseHasher, nameof(coinbaseHasher)); Contract.RequiresNonNull(headerHasher, nameof(headerHasher)); Contract.RequiresNonNull(blockHasher, nameof(blockHasher)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.poolConfig = poolConfig; this.clusterConfig = clusterConfig; this.clock = clock; this.poolAddressDestination = poolAddressDestination; this.networkType = networkType; if (ZCashConstants.CoinbaseTxConfig.TryGetValue(poolConfig.Coin.Type, out var coinbaseTx)) { coinbaseTx.TryGetValue(networkType, out coinbaseTxConfig); } BlockTemplate = blockTemplate; JobId = jobId; Difficulty = new Target(new NBitcoin.BouncyCastle.Math.BigInteger(BlockTemplate.Target, 16)).Difficulty; this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; this.headerHasher = headerHasher; this.blockHasher = blockHasher; blockTargetValue = BigInteger.Parse(BlockTemplate.Target, NumberStyles.HexNumber); previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseArray() .ToHexString(); blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; if (coinbaseTxConfig?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; if (!founders.HasValue) { throw new Exception("Error, founders reward missing for block template"); } blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; } rewardFees = blockTemplate.Transactions.Sum(x => x.Fee); BuildCoinbase(); // build tx hashes var txHashes = new List <uint256> { new uint256(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.Hash.HexToByteArray().ReverseArray()))); // build merkle root merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseArray(); merkleRootReversed = merkleRoot.ReverseArray(); merkleRootReversedHex = merkleRootReversed.ToHexString(); }
public override void Init(ZCashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, BitcoinNetworkType networkType, bool isPoS, double shareMultiplier, decimal?blockrewardMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.RequiresNonNull(coinbaseHasher, nameof(coinbaseHasher)); Contract.RequiresNonNull(headerHasher, nameof(headerHasher)); Contract.RequiresNonNull(blockHasher, nameof(blockHasher)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.poolConfig = poolConfig; this.clusterConfig = clusterConfig; this.clock = clock; this.poolAddressDestination = poolAddressDestination; this.networkType = networkType; if (ZCashConstants.Chains.TryGetValue(poolConfig.Coin.Type, out var coinbaseTx)) { coinbaseTx.TryGetValue(networkType, out chainConfig); } BlockTemplate = blockTemplate; JobId = jobId; Difficulty = (double)new BigRational(chainConfig.Diff1b, BlockTemplate.Target.HexToByteArray().ReverseArray().ToBigInteger()); this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; this.headerHasher = headerHasher; this.blockHasher = blockHasher; this.equihash = chainConfig.Solver(); if (!string.IsNullOrEmpty(BlockTemplate.Target)) { blockTargetValue = new uint256(BlockTemplate.Target); } else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseArray() .ToHexString(); BuildCoinbase(); // build tx hashes var txHashes = new List <uint256> { new uint256(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.TxId.HexToByteArray().ReverseArray()))); // build merkle root merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseArray(); merkleRootReversed = merkleRoot.ReverseArray(); merkleRootReversedHex = merkleRootReversed.ToHexString(); jobParams = new object[] { JobId, BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), previousBlockHashReversedHex, merkleRootReversedHex, BlockTemplate.Height.ReverseByteOrder().ToStringHex8() + sha256Empty.Take(28).ToHexString(), // height + hashReserved BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), BlockTemplate.Bits.HexToByteArray().ReverseArray().ToHexString(), false }; }
public virtual void Init(EquihashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, Network network, EquihashSolver solver) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.RequiresNonNull(solver, nameof(solver)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.clock = clock; this.poolAddressDestination = poolAddressDestination; coin = poolConfig.Template.As <EquihashCoinTemplate>(); networkParams = coin.GetNetwork(network.NetworkType); this.network = network; BlockTemplate = blockTemplate; JobId = jobId; Difficulty = (double)new BigRational(networkParams.Diff1BValue, BlockTemplate.Target.HexToReverseByteArray().AsSpan().ToBigInteger()); // ZCash Sapling & Overwinter support isSaplingActive = networkParams.SaplingActivationHeight.HasValue && networkParams.SaplingTxVersion.HasValue && networkParams.SaplingTxVersionGroupId.HasValue && networkParams.SaplingActivationHeight.Value > 0 && blockTemplate.Height >= networkParams.SaplingActivationHeight.Value; isOverwinterActive = isSaplingActive || networkParams.OverwinterTxVersion.HasValue && networkParams.OverwinterTxVersionGroupId.HasValue && networkParams.OverwinterActivationHeight.HasValue && networkParams.OverwinterActivationHeight.Value > 0 && blockTemplate.Height >= networkParams.OverwinterActivationHeight.Value; if (isSaplingActive) { txVersion = networkParams.SaplingTxVersion.Value; txVersionGroupId = networkParams.SaplingTxVersionGroupId.Value; } else if (isOverwinterActive) { txVersion = networkParams.OverwinterTxVersion.Value; txVersionGroupId = networkParams.OverwinterTxVersionGroupId.Value; } // Misc this.solver = solver; if (!string.IsNullOrEmpty(BlockTemplate.Target)) { blockTargetValue = new uint256(BlockTemplate.Target); } else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseInPlace() .ToHexString(); if (blockTemplate.Subsidy != null) { blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; } else { blockReward = BlockTemplate.CoinbaseValue; } if (networkParams?.vFundingStreams == true) { decimal fundingstreamTotal = 0; fundingstreamTotal = blockTemplate.Subsidy.FundingStreams.Sum(x => x.Value); blockReward = (blockTemplate.Subsidy.Miner + fundingstreamTotal) * BitcoinConstants.SatoshisPerBitcoin; } else if (networkParams?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; if (!founders.HasValue) { throw new Exception("Error, founders reward missing for block template"); } blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; } rewardFees = blockTemplate.Transactions.Sum(x => x.Fee); BuildCoinbase(); // build tx hashes var txHashes = new List <uint256> { new uint256(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.Hash.HexToReverseByteArray()))); // build merkle root merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseInPlace(); merkleRootReversed = merkleRoot.ReverseInPlace(); merkleRootReversedHex = merkleRootReversed.ToHexString(); // misc var hashReserved = isSaplingActive && !string.IsNullOrEmpty(blockTemplate.FinalSaplingRootHash) ? blockTemplate.FinalSaplingRootHash.HexToReverseByteArray().ToHexString() : sha256Empty.ToHexString(); var solutionIn = !string.IsNullOrEmpty(blockTemplate.Solution) ? blockTemplate.Solution.HexToByteArray().ToHexString() : null; jobParams = new object[] { JobId, BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), previousBlockHashReversedHex, merkleRootReversedHex, hashReserved, BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), BlockTemplate.Bits.HexToReverseByteArray().ToHexString(), false, solutionIn }; }
public override void Init(ZCashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, BitcoinNetworkType networkType, bool isPoS, double shareMultiplier, decimal?blockrewardMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.RequiresNonNull(coinbaseHasher, nameof(coinbaseHasher)); Contract.RequiresNonNull(headerHasher, nameof(headerHasher)); Contract.RequiresNonNull(blockHasher, nameof(blockHasher)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.poolConfig = poolConfig; this.clusterConfig = clusterConfig; this.clock = clock; this.poolAddressDestination = poolAddressDestination; this.networkType = networkType; if (ZCashConstants.Chains.TryGetValue(poolConfig.Coin.Type, out var chain)) { chain.TryGetValue(networkType, out chainConfig); } BlockTemplate = blockTemplate; JobId = jobId; Difficulty = (double)new BigRational(chainConfig.Diff1b, BlockTemplate.Target.HexToByteArray().ReverseArray().AsSpan().ToBigInteger()); txExpiryHeight = blockTemplate.Height + 100; // ZCash Sapling & Overwinter support isSaplingActive = chainConfig.SaplingActivationHeight.HasValue && chainConfig.SaplingTxVersion.HasValue && chainConfig.SaplingTxVersionGroupId.HasValue && chainConfig.SaplingActivationHeight.Value > 0 && blockTemplate.Height >= chainConfig.SaplingActivationHeight.Value; isOverwinterActive = isSaplingActive || chainConfig.OverwinterTxVersion.HasValue && chainConfig.OverwinterTxVersionGroupId.HasValue && chainConfig.OverwinterActivationHeight.HasValue && chainConfig.OverwinterActivationHeight.Value > 0 && blockTemplate.Height >= chainConfig.OverwinterActivationHeight.Value; if (isSaplingActive) { txVersion = chainConfig.SaplingTxVersion.Value; txVersionGroupId = chainConfig.SaplingTxVersionGroupId.Value; } else if (isOverwinterActive) { txVersion = chainConfig.OverwinterTxVersion.Value; txVersionGroupId = chainConfig.OverwinterTxVersionGroupId.Value; } // Misc this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; this.headerHasher = headerHasher; this.blockHasher = blockHasher; this.equihash = chainConfig.Solver(); if (!string.IsNullOrEmpty(BlockTemplate.Target)) { blockTargetValue = new uint256(BlockTemplate.Target); } else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseArray() .ToHexString(); blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; if (chainConfig?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; if (!founders.HasValue) { throw new Exception("Error, founders reward missing for block template"); } blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; } rewardFees = blockTemplate.Transactions.Sum(x => x.Fee); BuildCoinbase(); // build tx hashes var txHashes = new List <uint256> { new uint256(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.Hash.HexToByteArray().ReverseArray()))); // build merkle root merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseArray(); merkleRootReversed = merkleRoot.ReverseArray(); merkleRootReversedHex = merkleRootReversed.ToHexString(); // misc var hashReserved = isSaplingActive && !string.IsNullOrEmpty(blockTemplate.FinalSaplingRootHash) ? blockTemplate.FinalSaplingRootHash.HexToByteArray().ReverseArray().ToHexString() : sha256Empty.ToHexString(); jobParams = new object[] { JobId, BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), previousBlockHashReversedHex, merkleRootReversedHex, hashReserved, BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), BlockTemplate.Bits.HexToByteArray().ReverseArray().ToHexString(), false }; }
public MerkleNode GetMerkleRoot() { return(MerkleNode.GetRoot(this.Transactions.Select(t => t.GetHash()))); }
public override void Init(ZCashBlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, XPoolConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, BitcoinNetworkType networkType, bool isPoS, double shareMultiplier, decimal blockrewardMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) { Assertion.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Assertion.RequiresNonNull(poolConfig, nameof(poolConfig)); Assertion.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Assertion.RequiresNonNull(clock, nameof(clock)); Assertion.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Assertion.RequiresNonNull(coinbaseHasher, nameof(coinbaseHasher)); Assertion.RequiresNonNull(headerHasher, nameof(headerHasher)); Assertion.RequiresNonNull(blockHasher, nameof(blockHasher)); Assertion.Requires<ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.poolConfig = poolConfig; this.clusterConfig = clusterConfig; this.clock = clock; this.poolAddressDestination = poolAddressDestination; this.networkType = networkType; if (ZCashConstants.CoinbaseTxConfig.TryGetValue(poolConfig.Coin.Type, out var coinbaseTx)) coinbaseTx.TryGetValue(networkType, out coinbaseTxConfig); BlockTemplate = blockTemplate; JobId = jobId; Difficulty = (double) new BigRational(coinbaseTxConfig.Diff1b, BlockTemplate.Target.HexToByteArray().ReverseArray().ToBigInteger()); this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; this.headerHasher = headerHasher; this.blockHasher = blockHasher; if (!string.IsNullOrEmpty(BlockTemplate.Target)) blockTargetValue = new uint256(BlockTemplate.Target); else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseArray() .ToHexString(); blockReward = blockTemplate.Subsidy.Miner * BitcoinConstants.SatoshisPerBitcoin; if (coinbaseTxConfig?.PayFoundersReward == true) { var founders = blockTemplate.Subsidy.Founders ?? blockTemplate.Subsidy.Community; if (!founders.HasValue) throw new Exception("Error, founders reward missing for block template"); blockReward = (blockTemplate.Subsidy.Miner + founders.Value) * BitcoinConstants.SatoshisPerBitcoin; } rewardFees = blockTemplate.Transactions.Sum(x => x.Fee); BuildCoinbase(); var txHashes = new List<uint256> { new uint256(coinbaseInitialHash) }; txHashes.AddRange(BlockTemplate.Transactions.Select(tx => new uint256(tx.Hash.HexToByteArray().ReverseArray()))); merkleRoot = MerkleNode.GetRoot(txHashes).Hash.ToBytes().ReverseArray(); merkleRootReversed = merkleRoot.ReverseArray(); merkleRootReversedHex = merkleRootReversed.ToHexString(); jobParams = new object[] { JobId, BlockTemplate.Version.ReverseByteOrder().ToStringHex8(), previousBlockHashReversedHex, merkleRootReversedHex, sha256Empty.ToHexString(), BlockTemplate.CurTime.ReverseByteOrder().ToStringHex8(), BlockTemplate.Bits.HexToByteArray().ReverseArray().ToHexString(), false }; }