Commit 2d4e72d3 authored by Sergei Zubov's avatar Sergei Zubov

Fix mining on PoS network

From stratis PR#1634, commit df43989243138c05fb23cd549b7b71f60a336e35
parent 00b2e5bd
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
using NBitcoin.Protocol;
namespace NBitcoin.Networks
{
public class DeStreamMain : Network
{
public DeStreamMain()
{
string InitialWalletAddress = "TPPL2wmtxGzP8U6hQsGkRA9yCMsazB33ft";
decimal InitialCoins = 6000000000;
const string initialWalletAddress = "TPPL2wmtxGzP8U6hQsGkRA9yCMsazB33ft";
const decimal initialCoins = 6000000000;
const int numberOfEmissionTransactions = 6;
var messageStart = new byte[4];
messageStart[0] = 0x70;
messageStart[1] = 0x35;
messageStart[2] = 0x22;
messageStart[3] = 0x05;
var magic = BitConverter.ToUInt32(messageStart, 0);
uint magic = BitConverter.ToUInt32(messageStart, 0);
this.Name = "DeStreamMain";
this.RootFolderName = DeStreamRootFolderName;
......@@ -43,8 +41,10 @@ namespace NBitcoin.Networks
this.Consensus.BuriedDeployments[BuriedDeployments.BIP34] = 0;
this.Consensus.BuriedDeployments[BuriedDeployments.BIP65] = 0;
this.Consensus.BuriedDeployments[BuriedDeployments.BIP66] = 0;
this.Consensus.BIP34Hash = new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
this.Consensus.PowLimit = new Target(new uint256("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
this.Consensus.BIP34Hash =
new uint256("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
this.Consensus.PowLimit =
new Target(new uint256("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
this.Consensus.PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60); // two weeks
this.Consensus.PowTargetSpacing = TimeSpan.FromSeconds(10 * 60);
this.Consensus.PowAllowMinDifficultyBlocks = false;
......@@ -53,51 +53,40 @@ namespace NBitcoin.Networks
this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
this.Consensus.LastPOWBlock = 12500;
this.Consensus.IsProofOfStake = true;
this.Consensus.ConsensusFactory = new PosConsensusFactory() { Consensus = this.Consensus };
this.Consensus.ProofOfStakeLimit = new BigInteger(uint256.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ConsensusFactory = new PosConsensusFactory {Consensus = this.Consensus};
this.Consensus.ProofOfStakeLimit = new BigInteger(uint256
.Parse("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.ProofOfStakeLimitV2 = new BigInteger(uint256
.Parse("000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff").ToBytes(false));
this.Consensus.CoinType = 105;
this.Consensus.DefaultAssumeValid = new uint256("0x55a8205ae4bbf18f4d238c43f43005bd66e0b1f679b39e2c5c62cf6903693a5e"); // 795970
this.Consensus.DefaultAssumeValid =
new uint256("0x55a8205ae4bbf18f4d238c43f43005bd66e0b1f679b39e2c5c62cf6903693a5e"); // 795970
this.Consensus.MaxMoney = long.MaxValue;
this.Checkpoints = new Dictionary<int, CheckpointInfo>
{
{ 0, new CheckpointInfo(new uint256("0x0000066e91e46e5a264d42c89e1204963b2ee6be230b443e9159020539d972af"), new uint256("0x0000000000000000000000000000000000000000000000000000000000000000")) },
{ 2, new CheckpointInfo(new uint256("0xbca5936f638181e74a5f1e9999c95b0ce77da48c2688399e72bcc53a00c61eff"), new uint256("0x7d61c139a471821caa6b7635a4636e90afcfe5e195040aecbc1ad7d24924db1e")) }, // Premine
{ 50, new CheckpointInfo(new uint256("0x0353b43f4ce80bf24578e7c0141d90d7962fb3a4b4b4e5a17925ca95e943b816"), new uint256("0x7c2af3b10d13f9d2bc6063baaf7f0860d90d870c994378144f9bf85d0d555061")) },
{ 100, new CheckpointInfo(new uint256("0x688468a8aa48cd1c2197e42e7d8acd42760b7e2ac4bcab9d18ac149a673e16f6"), new uint256("0xcf2b1e9e76aaa3d96f255783eb2d907bf6ccb9c1deeb3617149278f0e4a1ab1b")) },
{ 150, new CheckpointInfo(new uint256("0xe4ae9663519abec15e28f68bdb2cb89a739aee22f53d1573048d69141db6ee5d"), new uint256("0xa6c17173e958dc716cc0892ce33dad8bc327963d78a16c436264ceae43d584ce")) },
{ 127500, new CheckpointInfo(new uint256("0x4773ca7512489df22de03aa03938412fab5b46154b05df004b97bcbeaa184078"), new uint256("0x619743c02ebaff06b90fcc5c60c52dba8aa3fdb6ba3800aae697cbb3c5483f17")) },
{ 128943, new CheckpointInfo(new uint256("0x36bcaa27a53d3adf22b2064150a297adb02ac39c24263a5ceb73856832d49679"), new uint256("0xa3a6fd04e41fcaae411a3990aaabcf5e086d2d06c72c849182b27b4de8c2c42a")) },
{ 136601, new CheckpointInfo(new uint256("0xf5c5210c55ff1ef9c04715420a82728e1647f3473e31dc478b3745a97b4a6d10"), new uint256("0x42058fabe21f7b118a9e358eaf9ef574dadefd024244899e71f2f6d618161e16")) }, // Hardfork to V2 - Drifting Bug Fix
{ 170000, new CheckpointInfo(new uint256("0x22b10952e0cf7e85bfc81c38f1490708f195bff34d2951d193cc20e9ca1fc9d5"), new uint256("0xa4942a6c99cba397cf2b18e4b912930fe1e64a7413c3d97c5a926c2af9073091")) },
{ 200000, new CheckpointInfo(new uint256("0x2391dd493be5d0ff0ef57c3b08c73eefeecc2701b80f983054bb262f7a146989"), new uint256("0x253152d129e82c30c584197deb6833502eff3ec2f30014008f75842d7bb48453")) },
{ 250000, new CheckpointInfo(new uint256("0x681c70fab7c1527246138f0cf937f0eb013838b929fbe9a831af02a60fc4bf55"), new uint256("0x24eed95e00c90618aa9d137d2ee273267285c444c9cde62a25a3e880c98a3685")) },
{ 300000, new CheckpointInfo(new uint256("0xd10ca8c2f065a49ae566c7c9d7a2030f4b8b7f71e4c6fc6b2a02509f94cdcd44"), new uint256("0x39c4dd765b49652935524248b4de4ccb604df086d0723bcd81faf5d1c2489304")) },
{ 350000, new CheckpointInfo(new uint256("0xe2b76d1a068c4342f91db7b89b66e0f2146d3a4706c21f3a262737bb7339253a"), new uint256("0xd1dd94985eaaa028c893687a7ddf89143dcf0176918f958c2d01f33d64910399")) },
{ 390000, new CheckpointInfo(new uint256("0x4682737abc2a3257fdf4c3c119deb09cbac75981969e2ffa998b4f76b7c657bb"), new uint256("0xd84b204ee94499ff65262328a428851fb4f4d2741e928cdd088fdf1deb5413b8")) },
{ 394000, new CheckpointInfo(new uint256("0x42857fa2bc15d45cdcaae83411f755b95985da1cb464ee23f6d40936df523e9f"), new uint256("0x2314b336906a2ed2a39cbdf6fc0622530709c62dbb3a3729de17154fc9d1a7c4")) },
{ 528000, new CheckpointInfo(new uint256("0x7aff2c48b398446595d01e27b5cd898087cec63f94ff73f9ad695c6c9bcee33a"), new uint256("0x3bdc865661390c7681b078e52ed3ad3c53ec7cff97b8c45b74abed3ace289fcc")) },
{ 576000, new CheckpointInfo(new uint256("0xe705476b940e332098d1d5b475d7977312ff8c08cbc8256ce46a3e2c6d5408b8"), new uint256("0x10e31bb5e245ea19650280cfd3ac1a76259fa0002d02e861d2ab5df290534b56")) },
};
this.Checkpoints = new Dictionary<int, CheckpointInfo>();
// TODO: Add genesis and premine block to Checkpoints
// First parameter - block height
// { 0, new CheckpointInfo(new uint256("0x00000e246d7b73b88c9ab55f2e5e94d9e22d471def3df5ea448f5576b1d156b9"), new uint256("0x0000000000000000000000000000000000000000000000000000000000000000")) },
this.Base58Prefixes = new byte[12][];
this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS] = new byte[] { (63) };
this.Base58Prefixes[(int)Base58Type.SCRIPT_ADDRESS] = new byte[] { (125) };
this.Base58Prefixes[(int)Base58Type.SECRET_KEY] = new byte[] { (63 + 128) };
this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_NO_EC] = new byte[] { 0x01, 0x42 };
this.Base58Prefixes[(int)Base58Type.ENCRYPTED_SECRET_KEY_EC] = new byte[] { 0x01, 0x43 };
this.Base58Prefixes[(int)Base58Type.EXT_PUBLIC_KEY] = new byte[] { (0x04), (0x88), (0xB2), (0x1E) };
this.Base58Prefixes[(int)Base58Type.EXT_SECRET_KEY] = new byte[] { (0x04), (0x88), (0xAD), (0xE4) };
this.Base58Prefixes[(int)Base58Type.PASSPHRASE_CODE] = new byte[] { 0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2 };
this.Base58Prefixes[(int)Base58Type.CONFIRMATION_CODE] = new byte[] { 0x64, 0x3B, 0xF6, 0xA8, 0x9A };
this.Base58Prefixes[(int)Base58Type.STEALTH_ADDRESS] = new byte[] { 0x2a };
this.Base58Prefixes[(int)Base58Type.ASSET_ID] = new byte[] { 23 };
this.Base58Prefixes[(int)Base58Type.COLORED_ADDRESS] = new byte[] { 0x13 };
this.Base58Prefixes[(int) Base58Type.PUBKEY_ADDRESS] = new byte[] {63};
this.Base58Prefixes[(int) Base58Type.SCRIPT_ADDRESS] = new byte[] {125};
this.Base58Prefixes[(int) Base58Type.SECRET_KEY] = new byte[] {63 + 128};
this.Base58Prefixes[(int) Base58Type.ENCRYPTED_SECRET_KEY_NO_EC] = new byte[] {0x01, 0x42};
this.Base58Prefixes[(int) Base58Type.ENCRYPTED_SECRET_KEY_EC] = new byte[] {0x01, 0x43};
this.Base58Prefixes[(int) Base58Type.EXT_PUBLIC_KEY] = new byte[] {0x04, 0x88, 0xB2, 0x1E};
this.Base58Prefixes[(int) Base58Type.EXT_SECRET_KEY] = new byte[] {0x04, 0x88, 0xAD, 0xE4};
this.Base58Prefixes[(int) Base58Type.PASSPHRASE_CODE] =
new byte[] {0x2C, 0xE9, 0xB3, 0xE1, 0xFF, 0x39, 0xE2};
this.Base58Prefixes[(int) Base58Type.CONFIRMATION_CODE] = new byte[] {0x64, 0x3B, 0xF6, 0xA8, 0x9A};
this.Base58Prefixes[(int) Base58Type.STEALTH_ADDRESS] = new byte[] {0x2a};
this.Base58Prefixes[(int) Base58Type.ASSET_ID] = new byte[] {23};
this.Base58Prefixes[(int) Base58Type.COLORED_ADDRESS] = new byte[] {0x13};
var encoder = new Bech32Encoder("bc");
this.Bech32Encoders = new Bech32Encoder[2];
this.Bech32Encoders[(int)Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder;
this.Bech32Encoders[(int)Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder;
this.Bech32Encoders[(int) Bech32Type.WITNESS_PUBKEY_ADDRESS] = encoder;
this.Bech32Encoders[(int) Bech32Type.WITNESS_SCRIPT_ADDRESS] = encoder;
this.DNSSeeds = new List<DNSSeedData>
{
......@@ -105,45 +94,54 @@ namespace NBitcoin.Networks
new DNSSeedData("node2.destream.io", "node2.destream.io")
};
string[] seedNodes = { "95.128.181.103", "95.128.181.80" };
this.SeedNodes = ConvertToNetworkAddresses(seedNodes, this.DefaultPort).ToList();
string[] seedNodes = {"95.128.181.103", "95.128.181.80"};
this.SeedNodes = this.ConvertToNetworkAddresses(seedNodes, this.DefaultPort).ToList();
// Create the genesis block.
this.GenesisTime = 1470467000;
this.GenesisNonce = 1831645;
this.GenesisBits = 0x1e0fffff;
this.GenesisVersion = 1;
this.GenesisReward = Money.Coins(InitialCoins);
this.GenesisWalletAddress = InitialWalletAddress;
this.GenesisReward = Money.Coins(initialCoins);
this.GenesisWalletAddress = initialWalletAddress;
this.Genesis = CreateDeStreamGenesisBlock(this.Consensus.ConsensusFactory, this.GenesisTime, this.GenesisNonce, this.GenesisBits, this.GenesisVersion, this.GenesisReward, this.GenesisWalletAddress);
this.Genesis = this.CreateDeStreamGenesisBlock(this.Consensus.ConsensusFactory, this.GenesisTime,
this.GenesisNonce, this.GenesisBits, this.GenesisVersion, this.GenesisReward,
this.GenesisWalletAddress, numberOfEmissionTransactions);
this.Consensus.HashGenesisBlock = this.Genesis.GetHash();
// Assert(this.Consensus.HashGenesisBlock == uint256.Parse("c5974b227ccb19ebd97578285a5937bb4bfb6dcdbf473966d8a2f9c714a8dbb0"));
// Assert(this.Genesis.Header.HashMerkleRoot == uint256.Parse("9e3fff58fb1ba15a69198e22d99572fa024afb754bfe1d3b8d28b86fd9de62df"));
}
protected Block CreateDeStreamGenesisBlock(ConsensusFactory consensusFactory, uint nTime, uint nNonce, uint nBits, int nVersion, Money InitialCoins, string InitialWalletAddress)
protected Block CreateDeStreamGenesisBlock(ConsensusFactory consensusFactory, uint nTime, uint nNonce,
uint nBits, int nVersion, Money initialCoins, string initialWalletAddress,
uint numberOfEmissionTransactions)
{
string pszTimestamp = "DESTREAM IS THE FIRST DECENTRALIZED GLOBAL FINANCIAL ECOSYSTEM FOR STREAMERS";
const string pszTimestamp = "DESTREAM IS THE FIRST DECENTRALIZED GLOBAL FINANCIAL ECOSYSTEM FOR STREAMERS";
Transaction txNew = consensusFactory.CreateTransaction();
txNew.Version = 1;
txNew.Time = nTime;
txNew.AddInput(new TxIn()
txNew.AddInput(new TxIn
{
ScriptSig = new Script(Op.GetPushOp(0), new Op()
ScriptSig = new Script(Op.GetPushOp(0), new Op
{
Code = (OpcodeType)0x1,
PushData = new[] { (byte)42 }
Code = (OpcodeType) 0x1,
PushData = new[] {(byte) 42}
}, Op.GetPushOp(Encoders.ASCII.DecodeData(pszTimestamp)))
});
byte[] prefix = this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS];
byte[] destination_publicKey = Encoders.Base58Check.DecodeData(InitialWalletAddress).Skip(prefix.Length).ToArray();
Script destination = (new KeyId(new uint160(destination_publicKey))).ScriptPubKey;
byte[] prefix = this.Base58Prefixes[(int) Base58Type.PUBKEY_ADDRESS];
byte[] destination_publicKey =
Encoders.Base58Check.DecodeData(initialWalletAddress).Skip(prefix.Length).ToArray();
Script destination = new KeyId(new uint160(destination_publicKey)).ScriptPubKey;
txNew.AddOutput(new TxOut(InitialCoins, destination));
txNew.AddOutput(new Money(Money.Zero), new Script());
for (int i = 0; i < numberOfEmissionTransactions; i++)
{
txNew.AddOutput(new TxOut(initialCoins / numberOfEmissionTransactions, destination));
}
Block genesis = consensusFactory.CreateBlock();
genesis.Header.BlockTime = Utils.UnixTimeToDateTime(nTime);
genesis.Header.Bits = nBits;
......
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using NBitcoin.BouncyCastle.Math;
using NBitcoin.DataEncoders;
using NBitcoin.Protocol;
namespace NBitcoin.Networks
......@@ -12,8 +9,9 @@ namespace NBitcoin.Networks
{
public DeStreamTest() //: base()
{
string InitialWalletAddress = "TPPL2wmtxGzP8U6hQsGkRA9yCMsazB33ft";
decimal InitialCoins = 6000000000;
const string initialWalletAddress = "TAE5v2wDwkrCPTDN51ru4YSZ8KvnFFrUQc";
const decimal initialCoins = 6000000000;
const int numberOfEmissionTransactions = 6;
// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ASCII, not valid as UTF-8, and produce
......@@ -31,27 +29,29 @@ namespace NBitcoin.Networks
this.RPCPort = 0xDE10; // 56848,
this.CoinTicker = "TDST";
this.Consensus.PowLimit = new Target(new uint256("0000ffff00000000000000000000000000000000000000000000000000000000"));
this.Consensus.DefaultAssumeValid = new uint256("0x98fa6ef0bca5b431f15fd79dc6f879dc45b83ed4b1bbe933a383ef438321958e"); // 372652
this.Consensus.PowLimit =
new Target(new uint256("0000ffff00000000000000000000000000000000000000000000000000000000"));
this.Consensus.PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60); // two weeks
this.Consensus.PowTargetSpacing = TimeSpan.FromSeconds(10 * 60);
this.Consensus.PowAllowMinDifficultyBlocks = false;
this.Consensus.PowNoRetargeting = false;
this.Consensus.RuleChangeActivationThreshold = 1916; // 95% of 2016
this.Consensus.MinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
this.Consensus.LastPOWBlock = 12500;
this.Consensus.DefaultAssumeValid =
new uint256("0x98fa6ef0bca5b431f15fd79dc6f879dc45b83ed4b1bbe933a383ef438321958e"); // 372652
this.Consensus.CoinbaseMaturity = 10;
this.Consensus.MaxMoney = long.MaxValue;
this.Consensus.ProofOfWorkReward = Money.Zero;
this.Base58Prefixes[(int)Base58Type.PUBKEY_ADDRESS] = new byte[] { (65) };
this.Base58Prefixes[(int)Base58Type.SCRIPT_ADDRESS] = new byte[] { (196) };
this.Base58Prefixes[(int)Base58Type.SECRET_KEY] = new byte[] { (65 + 128) };
this.Base58Prefixes[(int) Base58Type.PUBKEY_ADDRESS] = new byte[] {65};
this.Base58Prefixes[(int) Base58Type.SCRIPT_ADDRESS] = new byte[] {196};
this.Base58Prefixes[(int) Base58Type.SECRET_KEY] = new byte[] {65 + 128};
this.Checkpoints = new Dictionary<int, CheckpointInfo>
{
{ 0, new CheckpointInfo(new uint256("0x00000e246d7b73b88c9ab55f2e5e94d9e22d471def3df5ea448f5576b1d156b9"), new uint256("0x0000000000000000000000000000000000000000000000000000000000000000")) },
{ 2, new CheckpointInfo(new uint256("0x56959b1c8498631fb0ca5fe7bd83319dccdc6ac003dccb3171f39f553ecfa2f2"), new uint256("0x13f4c27ca813aefe2d9018077f8efeb3766796b9144fcc4cd51803bf4376ab02")) },
{ 50000, new CheckpointInfo(new uint256("0xb42c18eacf8fb5ed94eac31943bd364451d88da0fd44cc49616ffea34d530ad4"), new uint256("0x824934ddc5f935e854ac59ae7f5ed25f2d29a7c3914cac851f3eddb4baf96d78")) },
{ 100000, new CheckpointInfo(new uint256("0xf9e2f7561ee4b92d3bde400d251363a0e8924204c326da7f4ad9ccc8863aad79"), new uint256("0xdef8d92d20becc71f662ee1c32252aca129f1bf4744026b116d45d9bfe67e9fb")) },
{ 150000, new CheckpointInfo(new uint256("0x08b7c20a450252ddf9ce41dbeb92ecf54932beac9090dc8250e933ad3a175381"), new uint256("0xf05dad15f733ae0acbd34adc449be9429099dbee5fa9ecd8e524cf28e9153adb")) },
{ 200000, new CheckpointInfo(new uint256("0x8609cc873222a0573615788dc32e377b88bfd6a0015791f627d969ee3a415115"), new uint256("0xfa28c1f20a8162d133607c6a1c8997833befac3efd9076567258a7683ac181fa")) },
{ 250000, new CheckpointInfo(new uint256("0xdd664e15ac679a6f3b96a7176303956661998174a697ad8231f154f1e32ff4a3"), new uint256("0x19fc0fa29418f8b19cbb6557c1c79dfd0eff6779c0eaaec5d245c5cdf3c96d78")) },
{ 300000, new CheckpointInfo(new uint256("0x2409eb5ae72c80d5b37c77903d75a8e742a33843ab633935ce6e5264db962e23"), new uint256("0xf5ec7af55516b8e264ed280e9a5dba0180a4a9d3713351bfea275b18f3f1514e")) },
{ 350000, new CheckpointInfo(new uint256("0x36811041e9060f4b4c26dc20e0850dca5efaabb60618e3456992e9c0b1b2120e"), new uint256("0xbfda55ef0756bcee8485e15527a2b8ca27ca877aa09c88e363ef8d3253cdfd1c")) },
{ 400000, new CheckpointInfo(new uint256("0xb6abcb933d3e3590345ca5d3abb697461093313f8886568ac8ae740d223e56f6"), new uint256("0xfaf5fcebee3ec0df5155393a99da43de18b12e620fef5edb111a791ecbfaa63a")) }
};
this.Checkpoints = new Dictionary<int, CheckpointInfo>();
// TODO: Add genesis and premine block to Checkpoints
// First parameter - block height
// { 0, new CheckpointInfo(new uint256("0x00000e246d7b73b88c9ab55f2e5e94d9e22d471def3df5ea448f5576b1d156b9"), new uint256("0x0000000000000000000000000000000000000000000000000000000000000000")) },
this.DNSSeeds = new List<DNSSeedData>
{
......@@ -69,17 +69,19 @@ namespace NBitcoin.Networks
this.GenesisNonce = 1831645;
this.GenesisBits = 0x1e0fffff;
this.GenesisVersion = 1;
this.GenesisReward = Money.Coins(InitialCoins);
this.GenesisWalletAddress = InitialWalletAddress;
this.GenesisReward = Money.Coins(initialCoins);
this.GenesisWalletAddress = initialWalletAddress;
this.Genesis = CreateDeStreamGenesisBlock(this.Consensus.ConsensusFactory, this.GenesisTime, this.GenesisNonce, this.GenesisBits, this.GenesisVersion, this.GenesisReward, this.GenesisWalletAddress);
this.Genesis.Header.Time = 1493909211;
this.Genesis = this.CreateDeStreamGenesisBlock(this.Consensus.ConsensusFactory, this.GenesisTime,
this.GenesisNonce, this.GenesisBits, this.GenesisVersion, this.GenesisReward,
this.GenesisWalletAddress, numberOfEmissionTransactions);
this.Genesis.Header.Time = (uint) new DateTimeOffset(2018,09,24,16,13,00, TimeSpan.FromHours(3)).ToUnixTimeSeconds();
this.Genesis.Header.Nonce = 2433759;
this.Genesis.Header.Bits = this.Consensus.PowLimit;
this.Consensus.HashGenesisBlock = this.Genesis.GetHash();
// Assert(this.Consensus.HashGenesisBlock == uint256.Parse("c5974b227ccb19ebd97578285a5937bb4bfb6dcdbf473966d8a2f9c714a8dbb0"));
// Assert(this.Genesis.Header.HashMerkleRoot == uint256.Parse("9e3fff58fb1ba15a69198e22d99572fa024afb754bfe1d3b8d28b86fd9de62df"));
// Assert(this.Consensus.HashGenesisBlock == uint256.Parse("c5974b227ccb19ebd97578285a5937bb4bfb6dcdbf473966d8a2f9c714a8dbb0"));
// Assert(this.Genesis.Header.HashMerkleRoot == uint256.Parse("9e3fff58fb1ba15a69198e22d99572fa024afb754bfe1d3b8d28b86fd9de62df"));
}
}
}
\ No newline at end of file
......@@ -8,17 +8,24 @@ namespace Stratis.Bitcoin.Features.Miner
/// <inheritdoc/>
public sealed class BlockProvider : IBlockProvider
{
private readonly Network network;
/// <summary>Defines how proof of work blocks are built.</summary>
private readonly PowBlockDefinition powBlockDefinition;
/// <summary>Defines how proof of stake blocks are built.</summary>
private readonly PosBlockDefinition posBlockDefinition;
/// <summary>Defines how proof of work blocks are built on a Proof-of-Stake network.</summary>
private readonly PosPowBlockDefinition posPowBlockDefinition;
/// <param name="definitions">A list of block definitions that the builder can utilize.</param>
public BlockProvider(IEnumerable<BlockDefinition> definitions)
public BlockProvider(Network network, IEnumerable<BlockDefinition> definitions)
{
this.network = network;
this.powBlockDefinition = definitions.OfType<PowBlockDefinition>().FirstOrDefault();
this.posBlockDefinition = definitions.OfType<PosBlockDefinition>().FirstOrDefault();
this.posPowBlockDefinition = definitions.OfType<PosPowBlockDefinition>().FirstOrDefault();
}
/// <inheritdoc/>
......@@ -30,6 +37,9 @@ namespace Stratis.Bitcoin.Features.Miner
/// <inheritdoc/>
public BlockTemplate BuildPowBlock(ChainedHeader chainTip, Script script)
{
if (this.network.Consensus.IsProofOfStake)
return this.posPowBlockDefinition.Build(chainTip, script);
return this.powBlockDefinition.Build(chainTip, script);
}
}
......
......@@ -9,19 +9,19 @@ namespace Stratis.Bitcoin.Features.Miner.Interfaces
/// Generates up to a specified number of blocks with a limited number of attempts.
/// </summary>
/// <param name="reserveScript">The reserve script.</param>
/// <param name="generate">Number of blocks to generate. It is possible that less than the required number of blocks will be mined.</param>
/// <param name="amountOfBlocksToMine">Number of blocks to generate. It is possible that less than the required number of blocks will be mined.</param>
/// <param name="maxTries">Maximum number of attempts the miner will calculate PoW hash in order to find suitable ones to generate specified amount of blocks.</param>
/// <returns>List with generated block's hashes</returns>
List<uint256> GenerateBlocks(ReserveScript reserveScript, ulong generate, ulong maxTries);
List<uint256> GenerateBlocks(ReserveScript reserveScript, ulong amountOfBlocksToMine, ulong maxTries);
/// <summary>
/// Increments or resets the extra nonce based on the previous hash block value on on the pow miner and the passed nExtraNonce.
/// </summary>
/// <param name="pblock">The template block.</param>
/// <param name="pindexPrev">The previous chained block.</param>
/// <param name="nExtraNonce">The extra nonce counter.</param>
/// <param name="block">The template block.</param>
/// <param name="previousHeader">The previous chained block.</param>
/// <param name="extraNonce">The extra nonce counter.</param>
/// <returns>The new extra nonce after incrementing.</returns>
int IncrementExtraNonce(Block pblock, ChainedHeader pindexPrev, int nExtraNonce);
int IncrementExtraNonce(Block block, ChainedHeader previousHeader, int extraNonce);
/// <summary>
/// Starts a new async mining loop or returns the existing running mining loop.
......
......@@ -254,6 +254,7 @@ namespace Stratis.Bitcoin.Features.Miner
services.AddSingleton<IBlockProvider, BlockProvider>();
services.AddSingleton<BlockDefinition, PowBlockDefinition>();
services.AddSingleton<BlockDefinition, PosBlockDefinition>();
services.AddSingleton<BlockDefinition, PosPowBlockDefinition>();
services.AddSingleton<MinerController>();
services.AddSingleton<MiningRPCController>();
services.AddSingleton<MinerSettings>();
......
using Microsoft.Extensions.Logging;
using NBitcoin;
using Stratis.Bitcoin.Consensus;
using Stratis.Bitcoin.Features.Consensus;
using Stratis.Bitcoin.Features.Consensus.Interfaces;
using Stratis.Bitcoin.Features.MemoryPool;
using Stratis.Bitcoin.Features.MemoryPool.Interfaces;
using Stratis.Bitcoin.Mining;
using Stratis.Bitcoin.Utilities;
namespace Stratis.Bitcoin.Features.Miner
{
/// <summary>
/// Defines how a proof of work block will be built on a proof of stake network.
/// </summary>
public sealed class PosPowBlockDefinition : BlockDefinition
{
/// <summary>Instance logger.</summary>
private readonly ILogger logger;
/// <summary>Database of stake related data for the current blockchain.</summary>
private readonly IStakeChain stakeChain;
/// <summary>Provides functionality for checking validity of PoS blocks.</summary>
private readonly IStakeValidator stakeValidator;
public PosPowBlockDefinition(
IConsensusLoop consensusLoop,
IDateTimeProvider dateTimeProvider,
ILoggerFactory loggerFactory,
ITxMempool mempool,
MempoolSchedulerLock mempoolLock,
Network network,
IStakeChain stakeChain,
IStakeValidator stakeValidator)
: base(consensusLoop, dateTimeProvider, loggerFactory, mempool, mempoolLock, network)
{
this.logger = loggerFactory.CreateLogger(this.GetType().FullName);
this.stakeChain = stakeChain;
this.stakeValidator = stakeValidator;
}
/// <inheritdoc/>
public override void AddToBlock(TxMempoolEntry mempoolEntry)
{
this.logger.LogTrace("({0}.{1}:'{2}', {3}:{4})", nameof(mempoolEntry), nameof(mempoolEntry.TransactionHash), mempoolEntry.TransactionHash, nameof(mempoolEntry.ModifiedFee), mempoolEntry.ModifiedFee);
this.AddTransactionToBlock(mempoolEntry.Transaction);
this.UpdateBlockStatistics(mempoolEntry);
this.UpdateTotalFees(mempoolEntry.Fee);
this.logger.LogTrace("(-)");
}
/// <inheritdoc/>
public override BlockTemplate Build(ChainedHeader chainTip, Script scriptPubKey)
{
this.logger.LogTrace("({0}:'{1}',{2}.{3}:{4})", nameof(chainTip), chainTip, nameof(scriptPubKey), nameof(scriptPubKey.Length), scriptPubKey.Length);
this.OnBuild(chainTip, scriptPubKey);
this.logger.LogTrace("(-)");
return this.BlockTemplate;
}
/// <inheritdoc/>
public override void UpdateHeaders()
{
this.logger.LogTrace("()");
base.UpdateBaseHeaders();
this.block.Header.Bits = this.stakeValidator.GetNextTargetRequired(this.stakeChain, this.ChainTip, this.Network.Consensus, false);
this.logger.LogTrace("(-)");
}
}
}
\ No newline at end of file
......@@ -168,110 +168,199 @@ namespace Stratis.Bitcoin.Features.Miner
}
///<inheritdoc/>
public List<uint256> GenerateBlocks(ReserveScript reserveScript, ulong generate, ulong maxTries)
public List<uint256> GenerateBlocks(ReserveScript reserveScript, ulong amountOfBlocksToMine, ulong maxTries)
{
ulong nHeightStart = 0;
ulong nHeightEnd = 0;
ulong nHeight = 0;
var context = new MineBlockContext(amountOfBlocksToMine, (ulong)this.chain.Height, maxTries, reserveScript);
nHeightStart = (ulong)this.chain.Height;
nHeight = nHeightStart;
nHeightEnd = nHeightStart + generate;
int nExtraNonce = 0;
var blocks = new List<uint256>();
while (context.MiningCanContinue)
{
if (!this.ConsensusIsAtTip(context))
continue;
if (!this.BuildBlock(context))
continue;
if (!this.MineBlock(context))
break;
if (!this.ValidateMinedBlock(context))
continue;
if (!this.ValidateAndConnectBlock(context))
break;
if (!this.CheckValidationContextPreviousTip(context))
continue;
this.OnBlockMined(context);
}
while (nHeight < nHeightEnd)
return context.Blocks;
}
/// <summary>
/// Ensures that the node is synced before mining is allowed to start.
/// </summary>
private bool ConsensusIsAtTip(MineBlockContext context)
{
this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();
ChainedHeader chainTip = this.consensusLoop.Tip;
if (this.chain.Tip != chainTip)
context.ChainTip = this.consensusLoop.Tip;
if (this.chain.Tip != context.ChainTip)
{
Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
continue;
return false;
}
return true;
}
BlockTemplate blockTemplate = this.blockProvider.BuildPowBlock(chainTip, reserveScript.ReserveFullNodeScript);
/// <summary>
/// Creates a proof of work or proof of stake block depending on the network the node is running on.
/// <para>
/// If the node is on a POS network, make sure the POS consensus rules are valid. This is required for
/// generation of blocks inside tests, where it is possible to generate multiple blocks within one second.
/// </para>
/// </summary>
private bool BuildBlock(MineBlockContext context)
{
context.BlockTemplate = this.blockProvider.BuildPowBlock(context.ChainTip, context.ReserveScript.ReserveFullNodeScript);
if (this.network.Consensus.IsProofOfStake)
{
// Make sure the POS consensus rules are valid. This is required for generation of blocks inside tests,
// where it is possible to generate multiple blocks within one second.
if (blockTemplate.Block.Header.Time <= chainTip.Header.Time)
continue;
if (context.BlockTemplate.Block.Header.Time <= context.ChainTip.Header.Time)
return false;
}
nExtraNonce = this.IncrementExtraNonce(blockTemplate.Block, chainTip, nExtraNonce);
Block block = blockTemplate.Block;
return true;
}
/// <summary>
/// Executes until the required work (difficulty) has been reached. This is the "mining" process.
/// </summary>
private bool MineBlock(MineBlockContext context)
{
context.ExtraNonce = this.IncrementExtraNonce(context.BlockTemplate.Block, context.ChainTip, context.ExtraNonce);
while ((maxTries > 0) && (block.Header.Nonce < InnerLoopCount) && !block.CheckProofOfWork())
Block block = context.BlockTemplate.Block;
while ((context.MaxTries > 0) && (block.Header.Nonce < InnerLoopCount) && !block.CheckProofOfWork())
{
this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();
++block.Header.Nonce;
--maxTries;
--context.MaxTries;
}
if (maxTries == 0)
break;
if (context.MaxTries == 0)
return false;
if (block.Header.Nonce == InnerLoopCount)
continue;
return true;
}
var newChain = new ChainedHeader(block.Header, block.GetHash(), chainTip);
/// <summary>
/// Ensures that the block was properly mined by checking the block's work against the next difficulty target.
/// </summary>
private bool ValidateMinedBlock(MineBlockContext context)
{
if (context.BlockTemplate.Block.Header.Nonce == InnerLoopCount)
return false;
if (newChain.ChainWork <= chainTip.ChainWork)
continue;
var chainedHeader = new ChainedHeader(context.BlockTemplate.Block.Header, context.BlockTemplate.Block.GetHash(), context.ChainTip);
if (chainedHeader.ChainWork <= context.ChainTip.ChainWork)
return false;
var blockValidationContext = new ValidationContext { Block = block };
return true;
}
this.consensusLoop.AcceptBlockAsync(blockValidationContext).GetAwaiter().GetResult();
/// <summary>
/// Validate the mined block by passing it to the consensus rule engine.
/// <para>
/// On successfull block validation the block will be connected to the chain.
/// </para>
/// </summary>
private bool ValidateAndConnectBlock(MineBlockContext context)
{
context.ValidationContext = new ValidationContext { Block = context.BlockTemplate.Block };
this.consensusLoop.AcceptBlockAsync(context.ValidationContext).GetAwaiter().GetResult();
if (blockValidationContext.ChainedHeader == null)
if (context.ValidationContext.ChainedHeader == null)
{
this.logger.LogTrace("(-)[REORG-2]");
return blocks;
return false;
}
if (blockValidationContext.Error != null)
if (context.ValidationContext.Error != null && context.ValidationContext.Error != ConsensusErrors.InvalidPrevTip)
{
if (blockValidationContext.Error == ConsensusErrors.InvalidPrevTip)
continue;
this.logger.LogTrace("(-)[ACCEPT_BLOCK_ERROR]");
return blocks;
return false;
}
this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(blockValidationContext.Block) ? "POS" : "POW", blockValidationContext.ChainedHeader);
nHeight++;
blocks.Add(block.GetHash());
return true;
}
blockTemplate = null;
private bool CheckValidationContextPreviousTip(MineBlockContext context)
{
if (context.ValidationContext.Error != null)
if (context.ValidationContext.Error == ConsensusErrors.InvalidPrevTip)
return false;
return true;
}
return blocks;
private void OnBlockMined(MineBlockContext context)
{
this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(context.ValidationContext.Block) ? "POS" : "POW", context.ValidationContext.ChainedHeader);
context.CurrentHeight++;
context.Blocks.Add(context.BlockTemplate.Block.GetHash());
context.BlockTemplate = null;
}
///<inheritdoc/>
public int IncrementExtraNonce(Block pblock, ChainedHeader pindexPrev, int nExtraNonce)
public int IncrementExtraNonce(Block block, ChainedHeader previousHeader, int extraNonce)
{
// Update nExtraNonce
if (this.hashPrevBlock != pblock.Header.HashPrevBlock)
if (this.hashPrevBlock != block.Header.HashPrevBlock)
{
nExtraNonce = 0;
this.hashPrevBlock = pblock.Header.HashPrevBlock;
extraNonce = 0;
this.hashPrevBlock = block.Header.HashPrevBlock;
}
nExtraNonce++;
int nHeight = pindexPrev.Height + 1; // Height first in coinbase required for block.version=2
Transaction txCoinbase = pblock.Transactions[0];
txCoinbase.Inputs[0] = TxIn.CreateCoinbase(nHeight);
extraNonce++;
int height = previousHeader.Height + 1; // Height first in coinbase required for block.version=2
Transaction txCoinbase = block.Transactions[0];
txCoinbase.Inputs[0] = TxIn.CreateCoinbase(height);
Guard.Assert(txCoinbase.Inputs[0].ScriptSig.Length <= 100);
pblock.UpdateMerkleRoot();
block.UpdateMerkleRoot();
return nExtraNonce;
return extraNonce;
}
/// <summary>
/// Context class that holds information on the current state of the mining process (per block).
/// </summary>
private class MineBlockContext
{
private readonly ulong amountOfBlocksToMine;
public List<uint256> Blocks = new List<uint256>();
public BlockTemplate BlockTemplate { get; set; }
public ulong ChainHeight { get; set; }
public ulong CurrentHeight { get; set; }
public ChainedHeader ChainTip { get; set; }
public int ExtraNonce { get; set; }
public ulong MaxTries { get; set; }
public bool MiningCanContinue { get { return this.CurrentHeight < this.ChainHeight + this.amountOfBlocksToMine; } }
public readonly ReserveScript ReserveScript;
public ValidationContext ValidationContext { get; set; }
public MineBlockContext(ulong amountOfBlocksToMine, ulong chainHeight, ulong maxTries, ReserveScript reserveScript)
{
this.amountOfBlocksToMine = amountOfBlocksToMine;
this.ChainHeight = chainHeight;
this.CurrentHeight = chainHeight;
this.MaxTries = maxTries;
this.ReserveScript = reserveScript;
}
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Stratis Bitcoin Features Miner</Description>
<AssemblyTitle>Stratis.Bitcoin.Features.Miner</AssemblyTitle>
......@@ -17,18 +16,15 @@
<Version>1.1.12-beta</Version>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Stratis.Bitcoin.Features.Miner\**" />
<EmbeddedResource Remove="Stratis.Bitcoin.Features.Miner\**" />
<None Remove="Stratis.Bitcoin.Features.Miner\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NBitcoin\NBitcoin.csproj" />
<ProjectReference Include="..\Stratis.Bitcoin.Features.MemoryPool\Stratis.Bitcoin.Features.MemoryPool.csproj" />
......@@ -36,14 +32,12 @@
<ProjectReference Include="..\Stratis.Bitcoin.Features.Wallet\Stratis.Bitcoin.Features.Wallet.csproj" />
<ProjectReference Include="..\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1705;IDE0008;</NoWarn>
<DocumentationFile></DocumentationFile>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
</Project>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment