internal static void Receive(TcpReceiveState e, PoolCommand cmd) { var msg = new NonceDataMsg(); int index = 0; msg.Deserialize(cmd.Payload, ref index); var miner = PoolCache.WorkingMiners.FirstOrDefault(m => m.ClientAddress == e.Address); if (miner == null) { RejectCommand.Send(e); return; } var data = POC.CalculateScoopData(miner.WalletAddress, msg.MaxNonce, miner.CheckScoopNumber); if (Base16.Encode(data) == Base16.Encode(msg.ScoopData)) { miner.IsConnected = true; miner.ConnectedTime = Time.EpochTime; miner.LatestHeartbeatTime = Time.EpochTime; LoginCommand.SendLoginResult(e, true); LogHelper.Info(miner.ClientAddress + " login success"); StartCommand.Send(e); } else { LoginCommand.SendLoginResult(e, false); RejectCommand.Send(e); LogHelper.Info(miner.ClientAddress + " login fail"); } }
public IRpcMethodResult GetDifficulty() { try { var blockComponent = new BlockComponent(); var height = blockComponent.GetLatestHeight(); var newHeight = height + 1; var previousBlockMsg = blockComponent.GetBlockMsgByHeight(height); var prevStepBlockMsg = blockComponent.GetBlockMsgByHeight(newHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1); var bits = POC.CalculateBaseTarget(height, previousBlockMsg, prevStepBlockMsg).ToString(); var result = new GetDifficultyOM() { height = newHeight, hashTarget = bits }; return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult GetBaseTarget(long blockHeight) { try { var blockComponent = new BlockComponent(); BlockMsg lastBlock = null; BlockMsg prevStepBlock = null; if (blockHeight > 0) { lastBlock = blockComponent.GetBlockMsgByHeight(blockHeight - 1); prevStepBlock = blockComponent.GetBlockMsgByHeight(blockHeight - POC.DIFFIUCLTY_ADJUST_STEP); } long baseTarget; if (lastBlock != null) { baseTarget = POC.CalculateBaseTarget(blockHeight, lastBlock, prevStepBlock); } else { baseTarget = POC.CalculateBaseTarget(0, null, null); } return(Ok(baseTarget)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public IRpcMethodResult GetNewBlockReward() { try { var block = BlockDac.Default.SelectLast(); if (block == null) { var reward = POC.GetNewBlockReward(0); return(Ok(reward)); } else { var reward = POC.GetNewBlockReward(block.Header.Height); return(Ok(reward)); } } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public async Task <bool> Update(POC poc) { ReplaceOneResult updated = await context1.POCs.ReplaceOneAsync(filter : g => g.Id == poc.Id, replacement : poc); return(updated.IsAcknowledged && updated.ModifiedCount > 0); }
public bool ForgeBlock(BlockMsg blockMsg) { LogHelper.Info("Forge Block 8"); var hashResult = BlockHelper.GetMiningWorkResult(blockMsg); LogHelper.Info("Height:" + blockMsg.Header.Height); LogHelper.Info("Bits:" + POC.ConvertBitsToBigInt(blockMsg.Header.Bits).ToString("X").PadLeft(64, '0')); LogHelper.Info("Hash:" + Base16.Encode(hashResult)); LogHelper.Debug("Nonce:" + blockMsg.Header.Nonce); LogHelper.Debug("Address:" + blockMsg.Header.GeneratorId); if (!POC.Verify(blockMsg.Header.Bits, hashResult)) { LogHelper.Info("POC Verify Failed"); return(false); } LogHelper.Info("Forge Block 9"); var result = false; try { if (this.SubmitBlock(blockMsg)) { result = true; } LogHelper.Info($"Forge Block 10, {result}"); } catch (Exception ex) { LogHelper.Error(ex.ToString()); } finally { if (!result) { Thread.Sleep(60 * 1000); var nodeHeight = GetBlockHeight(); LogHelper.Info($"DB nodeHeight:{nodeHeight}, currentHeight:{blockMsg.Header.Height}"); if (nodeHeight >= blockMsg.Header.Height) { result = true; } else { result = false; } } } return(result); }
public bool VerifyBlock(BlockMsg newBlock) { //校验区块的基本信息 var result = VerifyBlockBasic(newBlock); if (!result) { return(false); } var txComponent = new TransactionComponent(); var blockComponent = new BlockComponent(); //校验交易信息 var totalFee = 0L; VerifyTransactionModel model = new VerifyTransactionModel(); model.block = newBlock; model.localHeight = blockComponent.GetLatestHeight(); foreach (var item in newBlock.Transactions) { long fee; model.transaction = item; if (txComponent.VerifyTransactionMsg(model, out fee)) { totalFee += fee; } else { return(false); } } if (Heights.Contains(newBlock.Header.Height)) { return(true); } var newBlockReward = POC.GetNewBlockReward(newBlock.Header.Height); var coinbaseAmount = newBlock.Transactions[0].Outputs[0].Amount; if (coinbaseAmount < 0 || coinbaseAmount != (totalFee + newBlockReward)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } return(true); }
//public List<MiningMsg> UpdateMiningPoolsBackup(List<MiningMsg> miningMsgs) //{ // List<MiningMsg> newMsgs = new List<MiningMsg>(); // if (miningMsgs == null || miningMsgs.Count == 0) // return newMsgs; // var items = miningMsgs.Where(x => HasMiningPool(x.Name, x.PublicKey)); // if (!items.Any()) // return newMsgs; // MiningPoolDac.Default.Put(items); // newMsgs.AddRange(miningMsgs); // CurrentMiningPools = this.GetAllMiningPoolsInDb(); // return newMsgs; //} public bool AddMiningToPool(MiningMsg msg) { if (HasMiningPool(msg.Name, msg.PublicKey)) { return(false); } if (!POC.VerifyMiningPoolSignature(msg.PublicKey, msg.Signature)) { return(false); } MiningPoolDac.Default.Put(msg); CurrentMiningPools = GetAllMiningPoolsInDb(); return(true); }
public static byte[] GetMiningWorkResult(BlockMsg block) { var listBytes = new List <Byte>(); listBytes.AddRange(Base16.Decode(block.Header.PayloadHash)); listBytes.AddRange(BitConverter.GetBytes(block.Header.Height)); var genHash = Sha3Helper.Hash(listBytes.ToArray()); var scoopNumber = POC.GetScoopNumber(block.Header.PayloadHash, block.Header.Height); var scoopData = POC.CalculateScoopData(block.Header.GeneratorId, block.Header.Nonce, scoopNumber); List <byte> targetByteLists = new List <byte>(); targetByteLists.AddRange(scoopData); targetByteLists.AddRange(genHash); var baseTarget = Sha3Helper.Hash(targetByteLists.ToArray()); return(baseTarget); }
public IRpcMethodResult GetBaseTarget(long blockHeight) { try { var blockComponent = new BlockComponent(); BlockMsg lastBlock = null; BlockMsg prevStepBlock = null; if (blockHeight > 0) { lastBlock = blockComponent.GetBlockMsgByHeight(blockHeight - 1); if (blockHeight >= POC.DIFFIUCLTY_ADJUST_STEP) { long prevStepHeight = 0; if (!GlobalParameters.IsTestnet && blockHeight <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = blockHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = blockHeight - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = blockComponent.GetBlockMsgByHeight(prevStepHeight); } } long baseTarget; if (lastBlock != null) { baseTarget = POC.CalculateBaseTarget(blockHeight, lastBlock, prevStepBlock); } else { baseTarget = POC.CalculateBaseTarget(0, null, null); } return(Ok(baseTarget)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public List <Block> GetBlockEntityByHash(IEnumerable <string> hashes) { var blockMsgs = BlockDac.Default.SelectByHashes(hashes); List <Block> result = new List <Block>(); foreach (var msg in blockMsgs) { var entity = new Block { Hash = msg.Header.Hash, Version = msg.Header.Version, Height = msg.Header.Height, PreviousBlockHash = msg.Header.PreviousBlockHash, Bits = msg.Header.Bits, Nonce = msg.Header.Nonce, Timestamp = msg.Header.Timestamp, TotalAmount = msg.Transactions.SelectMany(x => x.Outputs).Sum(x => x.Amount), GeneratorId = msg.Header.GeneratorId, BlockSignature = msg.Header.BlockSignature, IsDiscarded = false, IsVerified = GlobalParameters.LocalHeight - msg.Header.Height >= 6 }; var totalfee = msg.Transactions[0].Outputs[0].Amount - POC.GetNewBlockReward(msg.Header.Height); if (totalfee > 0) { entity.TotalFee = totalfee; } var nextBlockMsg = blockMsgs.FirstOrDefault(x => x.Header.Height == entity.Height + 1); if (nextBlockMsg == null) { nextBlockMsg = BlockDac.Default.SelectByHeight(msg.Header.Height + 1); } if (entity != null) { entity.NextBlockHash = nextBlockMsg.Header.Hash; } result.Add(entity); } return(result); }
public IRpcMethodResult GetDifficulty() { try { var blockComponent = new BlockComponent(); var height = blockComponent.GetLatestHeight(); var newHeight = height + 1; var previousBlockEntity = blockComponent.GetBlockMsgByHeight(height); BlockMsg prevStepBlock = null; if (newHeight >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && newHeight <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = newHeight - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = newHeight - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = blockComponent.GetBlockMsgByHeight(prevStepHeight); } var bits = POC.CalculateBaseTarget(height, previousBlockEntity, prevStepBlock).ToString(); var result = new GetDifficultyOM() { height = newHeight, hashTarget = bits }; return(Ok(result)); } catch (CommonException ce) { return(Error(ce.ErrorCode, ce.Message, ce)); } catch (Exception ex) { return(Error(ErrorCode.UNKNOWN_ERROR, ex.Message, ex)); } }
public BlockDetail GetBlockDetail(string hash) { var block = BlockDac.Default.SelectByHash(hash); if (block == null) { return(null); } BlockDetail detail = new BlockDetail(); detail.TradeCount = block.Header.TotalTransaction; detail.TotalOutput = block.Transactions.SelectMany(x => x.Outputs).Where(x => x.Amount > 0).Sum(x => x.Amount); var reward = POC.GetNewBlockReward(block.Header.Height); detail.Height = block.Header.Height; detail.Timestamp = block.Header.Timestamp; detail.Difficulty = POC.CalculateDifficulty(block.Header.Bits); detail.Bits = block.Header.Bits; detail.Version = block.Header.Version; detail.Nonce = block.Header.Nonce; detail.BlockReward = reward; detail.Hash = block.Header.Hash; detail.PreviousBlockHash = block.Header.PreviousBlockHash; var nextHash = BlockDac.Default.GetBlockHashByHeight(detail.Height + 1); detail.NextBlockHash = nextHash; detail.TranList = new List <TransOM>(); block.Transactions.ForEach(x => { detail.TranList.Add(x.ConvertToDetail()); }); var tx = detail.TranList.Skip(0); var totalFee = tx.SelectMany(x => x.OutputList).Sum(x => x.Amount) - tx.SelectMany(x => x.InputList).Sum(x => x.Amount); detail.TransactionFees = totalFee; return(detail); }
public static void SaveBlockRates() { long difficulty = 0; if (PoolCenterJob.Current.CurrentStartMiningMsg != null) { var block = RedisManager.Current.GetDataInRedis <BlockMsg>(PoolCenterJob.Current.CurrentStartMiningMsg.Id); difficulty = Convert.ToInt64(POC.CalculateDifficulty(block.Header.Bits)); } else { var height = NodeApi.Current.GetBlockHeight(); var block = NodeApi.Current.GetBlockByHeight(height); difficulty = Convert.ToInt64(POC.CalculateDifficulty(block.Header.Bits)); } BlockRatesComponent component = new BlockRatesComponent(); component.SaveBlockRates(CenterCache.GenarateBlockCount, difficulty); CenterCache.GenarateBlockCount = 0; }
public bool AddMiningToPool(MiningMsg msg) { if (!POC.VerifyMiningPoolSignature(msg.PublicKey, msg.Signature)) { return(false); } var result = false; var item = currentMiningPools.FirstOrDefault(x => x.PublicKey == msg.PublicKey && x.Signature == msg.Signature); if (item == null) { MiningPoolDac miningPoolDac = new MiningPoolDac(); MiningPool miningPool = ConvertToMiningPool(msg); result = miningPoolDac.SaveToDB(miningPool) > 0; } else if (item.Name != msg.Name) { MiningPoolDac miningPoolDac = new MiningPoolDac(); MiningPool miningPool = new MiningPool() { Name = msg.Name, PublicKey = msg.PublicKey, Signature = msg.Signature }; miningPoolDac.UpdateMiningPool(miningPool); result = true; } if (result && OnNewMiningPoolHandle != null) { NewMiningPoolMsg newMsg = new NewMiningPoolMsg(); newMsg.MinerInfo = new MiningMsg() { Name = msg.Name, PublicKey = msg.PublicKey, Signature = msg.Signature }; OnNewMiningPoolHandle(newMsg); } return(false); }
private void StartMining() { var block = NodeApi.Current.GenerateMiningBlock(_startArgs.Name, _startArgs.Account); var currentScoopNumber = POC.GetScoopNumber(block.Header.PayloadHash, block.Header.Height); _startTime = Time.EpochTime; block.Header.Timestamp = _startTime; if (block.Header.Height != this.currentBlockHeight || this.currentBlockStartTime <= 0) { this.currentBlockStartTime = _startTime; this.currentBlockHeight = block.Header.Height; } StartMiningMsg startMiningMsg = StartMiningMsg.CreateNew(); startMiningMsg.BlockHeight = block.Header.Height; startMiningMsg.ScoopNumber = currentScoopNumber; startMiningMsg.StartTime = _startTime; var genHash = BlockHelper.GenHash(block.Header.PayloadHash, block.Header.Height); startMiningMsg.GenHash = Base16.Encode(genHash); startMiningMsg.BaseTarget = NodeApi.Current.GetBaseTarget(block.Header.Height); var blockKey = KeyHelper.GetBlockKey(startMiningMsg.Id); RedisManager.Current.SaveDataToRedis(blockKey, block); //MQApi.SendStartMsg(startMiningMsg); RabbitMQApi.SendStartMsg(startMiningMsg); CurrentStartMiningMsg = startMiningMsg; LogHelper.Info("Start MiningTask Id=" + startMiningMsg.Id + " ScoopNumber = " + startMiningMsg.ScoopNumber + " Height= " + startMiningMsg.BlockHeight); LogHelper.Info($"Block bits is {POC.ConvertBitsToBigInt(block.Header.Bits).ToString("X").PadLeft(64, '0')}"); LogHelper.Info($"StartMiningMsg.BaseTarget is {POC.ConvertBitsToBigInt(startMiningMsg.BaseTarget).ToString("X").PadLeft(64, '0')}"); LogHelper.Info($"Block height is {block.Header.Height}"); }
/// <summary> /// Called on each bar update event (incoming tick) /// </summary> protected override void OnBarUpdate() { int i; double AvgPrice = 0.0; double Variance = 0.0; double StandardDeviation = 0.0; if (CurrentBar < 10) { return; } if (InitializeEndTime) { if (Time[0].CompareTo(StartTime) >= 0) { InitializeEndTime = false; StartTime = new DateTime(Time[0].Year, Time[0].Month, Time[0].Day, OpenHour, OpenMinute, 0, 0, DateTimeKind.Utc); if (sessionLengthInHours >= 24.0) { EndTime = StartTime.AddHours(24.0 - 1.0 / 60.0); } else { EndTime = StartTime.AddHours(sessionLengthInHours); } } } if (!InitializeEndTime && Time[1].CompareTo(EndTime) <= 0 && Time[0].CompareTo(EndTime) > 0) { DetermineHighLowOfSession(StartTime); if (LastBarOfSession < 0) { return; } StartTime = new DateTime(Time[0].Year, Time[0].Month, Time[0].Day, OpenHour, OpenMinute, 0, 0, DateTimeKind.Utc); if (sessionLengthInHours >= 24) { EndTime = StartTime.AddHours(24.0 - 1.0 / 60.0); } else { EndTime = StartTime.AddHours(sessionLengthInHours); } int TicksInRange = (int)Math.Round((TheSessionHigh - TheSessionLow) / TickSize, 0); if (TicksInRange >= 1000) { Log("Potential data problem in CalculateValueArea at " + Time[0].ToString() + " Session H/L: " + TheSessionHigh.ToString(FormatString) + " / " + TheSessionLow.ToString(FormatString), LogLevel.Warning); } if (TicksInRange < 0) { Log("Potential data problem in CalculateValueArea at " + Time[0].ToString() + " Session H/L: " + TheSessionHigh.ToString(FormatString) + " / " + TheSessionLow.ToString(FormatString), LogLevel.Warning); } for (i = 0; i < 1000; i++) { PriceHitsArray[0, i] = (i * TickSize + TheSessionLow); PriceHitsArray[1, i] = 0.0; } int index = 0; i = 1; while (i <= LastBarOfSession) //Accumulate the volume for each previous days bar into PriceVolume array { if (!inclWeekendVol && (Time[i].DayOfWeek == DayOfWeek.Saturday || Time[i].DayOfWeek == DayOfWeek.Sunday)) { i++; } else { if (profileType == "VOC") //Volume On Close - puts all the volume for that bar on the close price { index = (int)Math.Round((Close[i] - TheSessionLow) / TickSize, 0); PriceHitsArray[1, index] = PriceHitsArray[1, index] + Volume[i]; } if (profileType == "TPO") //Time Price Opportunity - disregards volume, only counts number of times prices are touched { double BarH = High[i]; double BarP = Low[i]; while (BarP <= BarH + TickSize / 2.0) { index = (int)Math.Round((BarP - TheSessionLow) / TickSize, 0); PriceHitsArray[1, index] = PriceHitsArray[1, index] + 1; BarP = BarP + TickSize; } } if (profileType == "VWTPO") //Volume Weighted Time Price Opportunity - Disperses the Volume of the bar over the range of the bar so each price touched is weighted with volume { double BarH = High[i]; double BarP = Low[i]; int TicksInBar = (int)Math.Round((BarH - Low[i]) / TickSize + 1, 0); while (BarP <= BarH + TickSize / 2.0) { index = (int)Math.Round((BarP - TheSessionLow) / TickSize, 0); PriceHitsArray[1, index] = PriceHitsArray[1, index] + Volume[i] / TicksInBar; BarP = BarP + TickSize; } } i++; } } //Calculate the Average price as weighted by the hit counts AND find the price with the highest hits (POC price) i = 0; double THxP = 0.0; //Total of Hits multiplied by Price at that volume HitsTotal = 0.0; PriceOfPOC = 0.0; double MaxHits = 0.0; while (i <= TicksInRange) //Sum up Volume*Price in THxP...and sum up Volume in VolumeTotal { if (PriceHitsArray[1, i] > 0.0) { THxP = THxP + PriceHitsArray[1, i] * PriceHitsArray[0, i]; HitsTotal = HitsTotal + PriceHitsArray[1, i]; if (PriceHitsArray[1, i] > MaxHits) //used to determine POC level { MaxHits = PriceHitsArray[1, i]; PriceOfPOC = PriceHitsArray[0, i]; } } i++; } AvgPrice = THxP / HitsTotal; VAtop = AvgPrice; VAbot = AvgPrice; double ViA = 0.0; //This loop calculates the percentage of hits contained within the Value Area double TV = 0.00001; double Adj = 0.0; while (ViA / TV < pctOfVolumeInVA) { VAbot = VAbot - Adj; VAtop = VAtop + Adj; ViA = 0.0; TV = 0.00001; for (i = 0; i < 1000; i++) { if (PriceHitsArray[0, i] > VAbot - Adj && PriceHitsArray[0, i] < VAtop + Adj) { ViA = PriceHitsArray[1, i] + ViA; } TV = TV + PriceHitsArray[1, i]; } Adj = TickSize; } //DrawText("PctInValueArea",(ViA/TV).ToString("0.00"),50,TheSessionHigh,Color.Red); } if (VAtop > 0.0) { VAt.Set(VAtop); VAb.Set(VAbot); POC.Set(PriceOfPOC); } StartTime = new DateTime(Time[0].Year, Time[0].Month, Time[0].Day, OpenHour, OpenMinute, 0, 0, DateTimeKind.Utc); if (sessionLengthInHours >= 24.0) { EndTime = StartTime.AddHours(24.0 - 1.0 / 60.0); } else { EndTime = StartTime.AddHours(sessionLengthInHours); } }
public bool VerifyBlockBasic(BlockMsg newBlock) { if (newBlock.Header.Hash != newBlock.Header.GetHash()) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HASH_ERROR); } bool hasPreviousBlock = false; long previousBlockTimestamp = -1; long previousBlockBits = -1; long previousBlockHeight = newBlock.Header.Height - 1; var cacheBlockKey = $"{newBlock.Header.Hash}_{newBlock.Header.Height - 1}"; var previousBlockMsg = BlockDac.Default.SelectByHash(newBlock.Header.PreviousBlockHash); if (previousBlockMsg != null) { hasPreviousBlock = true; previousBlockTimestamp = previousBlockMsg.Header.Timestamp; previousBlockBits = previousBlockMsg.Header.Bits; } else { var previousBlock = BlockDac.Default.SelectByHash(newBlock.Header.PreviousBlockHash); hasPreviousBlock = previousBlock != null; if (hasPreviousBlock) { previousBlockTimestamp = previousBlock.Header.Timestamp; previousBlockBits = previousBlock.Header.Bits; } } if (newBlock.Header.Height > 0 && !hasPreviousBlock) { throw new CommonException(ErrorCode.Engine.Block.Verify.PREV_BLOCK_NOT_EXISTED); } if ((newBlock.Header.Timestamp - Time.EpochTime) > 2 * 60 * 60 * 1000 || (hasPreviousBlock && newBlock.Header.Timestamp <= previousBlockTimestamp)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_TIME_IS_ERROR); } if (newBlock.Serialize().Length > Consensus.BlockSetting.MAX_BLOCK_SIZE) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIZE_LARGE_THAN_LIMIT); } BlockMsg prevStepBlock = null; if (newBlock.Header.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && newBlock.Header.Height <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlock = BlockDac.Default.SelectByHeight(prevStepHeight); } //区块必须包含交易,否则错误 if (newBlock.Transactions == null || newBlock.Transactions.Count == 0) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.NOT_FOUND_COINBASE); } //第一个一定是coinbase,奖励+手续费 var coinbase = newBlock.Transactions[0]; //校验打包区块的矿池是否经过验证 var minerInfo = Encoding.UTF8.GetString(Base16.Decode(coinbase.Inputs[0].UnlockScript)).Split("`")[0]; var pool = MiningPoolComponent.CurrentMiningPools.FirstOrDefault(x => x.Name == minerInfo); if (pool == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.MINING_POOL_NOT_EXISTED); } //校验区块的签名信息 if (!POC.VerifyBlockSignature(newBlock.Header.PayloadHash, newBlock.Header.BlockSignature, pool.PublicKey)) { LogHelper.Warn($"PayloadHash::{newBlock.Header.PayloadHash}"); LogHelper.Warn($"BlockSignature::{newBlock.Header.BlockSignature}"); LogHelper.Warn($"PublicKey::{pool.PublicKey}"); throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIGNATURE_IS_ERROR); } if (POC.CalculateBaseTarget(newBlock.Header.Height, previousBlockBits, previousBlockTimestamp, prevStepBlock) != newBlock.Header.Bits) { throw new CommonException(ErrorCode.Engine.Block.Verify.BITS_IS_WRONG); } var targetResult = POC.CalculateTargetResult(newBlock); if (newBlock.Header.Height == 17687 || POC.Verify(newBlock.Header.Bits, targetResult)) { return(true); } else { throw new CommonException(ErrorCode.Engine.Block.Verify.POC_VERIFY_FAIL); } }
/// <summary> /// 创建新的区块 /// </summary> /// <param name="minerName"></param> /// <param name="generatorId"></param> /// <param name="accountId"></param> /// <returns></returns> public BlockMsg CreateNewBlock(string minerName, string generatorId, string remark = null, string accountId = null) { var accountDac = AccountDac.Default; var blockDac = BlockDac.Default; var txDac = TransactionDac.Default; var txPool = TransactionPool.Instance; var txComponent = new TransactionComponent(); var transactionMsgs = new List <TransactionMsg>(); long lastBlockHeight = -1; string lastBlockHash = Base16.Encode(HashHelper.EmptyHash()); long lastBlockBits = -1; string lastBlockGenerator = null; //获取最后一个区块 var blockEntity = blockDac.SelectLast(); if (blockEntity != null) { lastBlockHeight = blockEntity.Header.Height; lastBlockHash = blockEntity.Header.Hash; lastBlockBits = blockEntity.Header.Bits; lastBlockGenerator = blockEntity.Header.GeneratorId; } long totalSize = 0; long totalInput = 0; long totalOutput = 0; long totalAmount = 0; long totalFee = 0; long maxSize = Consensus.BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); //获取待打包的交易 var txs = txPool.GetTxsWithoutRepeatCost(10, maxSize); var hashIndexs = new List <string>(); foreach (var tx in txs) { totalSize += tx.Size; totalInput += tx.InputCount; totalOutput += tx.OutputCount; hashIndexs.AddRange(tx.Inputs.Select(x => $"{x.OutputTransactionHash}_{x.OutputIndex}")); long totalOutputAmount = tx.Outputs.Sum(x => x.Amount); totalAmount += totalOutputAmount; } var utxos = UtxoSetDac.Default.Get(hashIndexs); var totalInputAmount = utxos.Sum(x => x.Amount); totalFee = totalInputAmount - totalAmount; transactionMsgs.AddRange(txs); var accounts = AccountDac.Default.SelectAll(); var minerAccount = accounts.OrderBy(x => x.Timestamp).FirstOrDefault(); if (accountId != null) { var account = accounts.FirstOrDefault(x => x.Id == accountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { minerAccount = account; } } var minerAccountId = minerAccount.Id; BlockMsg newBlockMsg = new BlockMsg(); BlockHeaderMsg headerMsg = new BlockHeaderMsg(); headerMsg.Hash = Base16.Encode(HashHelper.EmptyHash()); headerMsg.GeneratorId = generatorId; newBlockMsg.Header = headerMsg; headerMsg.Height = lastBlockHeight + 1; headerMsg.PreviousBlockHash = lastBlockHash; if (headerMsg.Height == 0) { minerAccountId = Consensus.BlockSetting.GenesisBlockReceiver; remark = Consensus.BlockSetting.GenesisBlockRemark; } BlockMsg prevBlockMsg = null; BlockMsg prevStepBlockMsg = null; if (blockEntity != null) { prevBlockMsg = blockEntity; } if (headerMsg.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { var prevStepHeight = 0L; if (!GlobalParameters.IsTestnet && headerMsg.Height <= POC.DIFFICULTY_CALCULATE_LOGIC_ADJUST_HEIGHT) { prevStepHeight = headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1; } else { prevStepHeight = headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP; } prevStepBlockMsg = blockDac.SelectByHeight(prevStepHeight); } var newBlockReward = POC.GetNewBlockReward(headerMsg.Height); headerMsg.Bits = POC.CalculateBaseTarget(headerMsg.Height, prevBlockMsg, prevStepBlockMsg); headerMsg.TotalTransaction = transactionMsgs.Count + 1; var coinbaseTxMsg = new TransactionMsg(); coinbaseTxMsg.Timestamp = Time.EpochTime; coinbaseTxMsg.Locktime = 0; var coinbaseInputMsg = new InputMsg(); coinbaseTxMsg.Inputs.Add(coinbaseInputMsg); coinbaseInputMsg.OutputIndex = 0; coinbaseInputMsg.OutputTransactionHash = Base16.Encode(HashHelper.EmptyHash()); coinbaseInputMsg.UnlockScript = Script.BuildMinerScript(minerName, remark); coinbaseInputMsg.Size = coinbaseInputMsg.UnlockScript.Length; var coinbaseOutputMsg = new OutputMsg(); coinbaseTxMsg.Outputs.Add(coinbaseOutputMsg); coinbaseOutputMsg.Amount = newBlockReward + totalFee; coinbaseOutputMsg.LockScript = Script.BuildLockScipt(minerAccountId); coinbaseOutputMsg.Size = coinbaseOutputMsg.LockScript.Length; coinbaseOutputMsg.Index = 0; if (newBlockReward < 0 || totalFee < 0 || coinbaseOutputMsg.Amount < 0) { LogHelper.Warn($"newBlockReward:{newBlockReward}"); LogHelper.Warn($"totalFee:{totalFee}"); LogHelper.Warn($"coinbaseOutputMsg.Amount:{coinbaseOutputMsg.Amount}"); throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } coinbaseTxMsg.Hash = coinbaseTxMsg.GetHash(); newBlockMsg.Transactions.Insert(0, coinbaseTxMsg); foreach (var tx in transactionMsgs) { newBlockMsg.Transactions.Add(tx); } headerMsg.PayloadHash = newBlockMsg.GetPayloadHash(); LogHelper.Warn($"{headerMsg.Height}::{headerMsg.PayloadHash}"); LogHelper.Warn($"PayloadHash::{headerMsg.PayloadHash}"); LogHelper.Warn($"BlockSignature::{headerMsg.BlockSignature}"); LogHelper.Warn($"miner::{minerName}"); headerMsg.BlockSignature = Base16.Encode(HashHelper.EmptyHash()); headerMsg.BlockSigSize = headerMsg.BlockSignature.Length; headerMsg.TotalTransaction = newBlockMsg.Transactions.Count; return(newBlockMsg); }
internal static void Received(TcpReceiveState e, PoolCommand cmd) { var miner = PoolCache.WorkingMiners.FirstOrDefault(m => m.ClientAddress == e.Address && m.IsConnected); if (miner == null) { LogHelper.Info("Received invalid scoop data from " + e.Address); LogHelper.Info("Miner logout"); PoolJob.TcpServer.CloseSocket(e); return; } if (PoolCache.CurrentTask == null || PoolCache.CurrentTask.State != MiningState.Mining) { return; } var msg = new ScoopDataMsg(); int index = 0; msg.Deserialize(cmd.Payload, ref index); PoolCache.CurrentTask.LastReceiveTime = Time.EpochTime; var minerinfo = PoolCache.CurrentTask.MinerEfforts.FirstOrDefault(x => x.Account == miner.WalletAddress); if (minerinfo == null) { PoolCache.CurrentTask.MinerEfforts.Add(new Models.MinerEffort { Account = miner.WalletAddress, Effort = 1 }); } else { if (minerinfo.Effort == Setting.MaxNonceCount) { RejectCommand.Send(e); return; } minerinfo.Effort++; } if (msg.BlockHeight != PoolCache.CurrentTask.CurrentBlockHeight) { LogHelper.Info("Received invalid scoop data from " + e.Address + ", nonce is " + msg.Nonce + ", height is " + msg.BlockHeight); LogHelper.Info("Block Height invalid , Stop and Send StartMsg"); var stopMsg = new StopMsg { BlockHeight = msg.BlockHeight, Result = false, StartTime = Time.EpochTime, StopTime = Time.EpochTime }; StopCommand.Send(e, stopMsg); Task.Delay(1000).Wait(); var startMsg = PoolCache.CurrentTask.CurrentStartMsg; if (startMsg != null) { StartCommand.Send(e, startMsg); } return; } LogHelper.Info("Received scoop data from " + miner.ClientAddress + ", nonce is " + msg.Nonce + ", scoop number is " + msg.ScoopNumber + ", block height is " + msg.BlockHeight); if (msg.ScoopNumber != PoolCache.CurrentTask.CurrentScoopNumber) { LogHelper.Info("Received invalid scoop data from " + e.Address + ", nonce is " + msg.Nonce + ", ScoopNumber is " + PoolCache.CurrentTask.CurrentScoopNumber + "/" + msg.ScoopNumber); LogHelper.Info("Scoop Number invalid"); return; } var verResult = POC.Verify(PoolCache.CurrentTask.BaseTarget, msg.Target); LogHelper.Debug("Bits:" + POC.ConvertBitsToBigInt(PoolCache.CurrentTask.BaseTarget).ToString("X").PadLeft(64, '0')); LogHelper.Debug("Hash:" + Base16.Encode(msg.Target)); LogHelper.Debug("Verify Result is " + verResult); if (!verResult) { return; } ForgeMsg forgeMsg = new ForgeMsg(); forgeMsg.Account = msg.WalletAddress; forgeMsg.Nonce = msg.Nonce; forgeMsg.StartMsgId = PoolCache.CurrentTask.Id; //MQApi.SendForgeBlock(msg.WalletAddress, msg.Nonce, PoolCache.CurrentTask.Id); RabbitMQApi.SendForgeBlock(msg.WalletAddress, msg.Nonce, PoolCache.CurrentTask.Id); }
public static void SaveRewards(string startMsgId, long nonce, int height) { try { var block = RedisManager.Current.GetDataInRedis <BlockMsg>(startMsgId); if (block == null || block.Header.Height == 0) { return; } var miners = GetAllMiners(); var rewardAddresses = miners.Select(x => x.Address); Blocks blocks = new Blocks(); blocks.Generator = block.Header.GeneratorId; blocks.Hash = block.Header.GetHash(); blocks.Height = block.Header.Height; blocks.Nonce = nonce; var baseReward = POC.GetNewBlockReward(block.Header.Height); var totalReward = block.Transactions[0].Outputs[0].Amount; if (totalReward < baseReward) { totalReward = baseReward; } var totalRewardAllMiner = totalReward * 0.4; var totalRewardSuperNode = totalReward * 0.2; var totalRewardDepositInterest = totalReward * 0.4;//存币利息,需要派分到当前存币大于1的地址 var rewards = new List <RewardList>(); //矿工部分 long totalEffort = 0; foreach (var address in rewardAddresses) { var key = "Pool:MinerMaxNonce:" + address; var maxNonce = RedisManager.Current.GetDataInRedis <string>(key); if (string.IsNullOrEmpty(maxNonce)) { continue; } var effort = int.Parse(maxNonce); RewardList rewardList = new RewardList(); rewardList.BlockHash = blocks.Hash; rewardList.GenerateTime = blocks.Timstamp; rewardList.MinerAddress = address; rewardList.Hashes = effort; rewardList.TransactionHash = ""; rewardList.RewardType = 0; rewards.Add(rewardList); totalEffort += effort; } rewards.ForEach(x => { x.OriginalReward = (long)Math.Floor(totalRewardAllMiner * ((double)x.Hashes / (double)totalEffort)); x.ActualReward = x.OriginalReward; }); blocks.TotalHash = totalEffort; blocks.TotalReward = totalReward; //SuperNode部分 AwardSetting setting = ConfigurationTool.GetAppSettings <AwardSetting>("OmniCoin.MiningPool.Business.conf.json", "AwardSetting"); var superNodeReward = (long)totalRewardSuperNode; rewards.Add(new RewardList { OriginalReward = superNodeReward, ActualReward = superNodeReward, BlockHash = blocks.Hash, GenerateTime = blocks.Timstamp, MinerAddress = setting.SuperNodeAddress, Hashes = 0, TransactionHash = "", RewardType = 1 }); //DepositInterest部分 var currentDepositLists = new RewardListComponent().GetAllNotExpiredDeposit(); if (currentDepositLists != null && currentDepositLists.Any()) { var totalDepositAmount = currentDepositLists.Sum(x => x.Amount); currentDepositLists.ForEach(x => { //利息 = 当前数量 / 总数量 * (Coinbase * 40 % 奖励) var interest = (long)Math.Floor(totalRewardDepositInterest * ((double)x.Amount / (double)totalDepositAmount)); rewards.Add(new RewardList { OriginalReward = interest, ActualReward = interest, BlockHash = blocks.Hash, GenerateTime = blocks.Timstamp, MinerAddress = x.Address, Hashes = 0, TransactionHash = "", AddressDepositTotalAmount = x.Amount, DepositTotalAmount = totalDepositAmount, RewardType = 2, DepositTransactionHash = x.TransactionHash }); }); } var blockComponent = new BlocksComponent(); blockComponent.SaveBlockAndRewardLists(blocks, rewards); } catch (Exception ex) { LogHelper.Error(ex.ToString()); } }
/// <summary> /// 创建新的区块 /// </summary> /// <param name="minerName"></param> /// <param name="generatorId"></param> /// <param name="accountId"></param> /// <returns></returns> public BlockMsg CreateNewBlock(string minerName, string generatorId, string remark = null, string accountId = null) { var accountDac = new AccountDac(); var blockDac = new BlockDac(); var outputDac = new OutputDac(); var txDac = new TransactionDac(); var txPool = TransactionPool.Instance; var transactionMsgs = new List <TransactionMsg>(); long lastBlockHeight = -1; string lastBlockHash = Base16.Encode(HashHelper.EmptyHash()); long lastBlockBits = -1; string lastBlockGenerator = null; //获取最后一个区块 var blockEntity = blockDac.SelectLast(); if (blockEntity != null) { lastBlockHeight = blockEntity.Height; lastBlockHash = blockEntity.Hash; lastBlockBits = blockEntity.Bits; lastBlockGenerator = blockEntity.GeneratorId; } long totalSize = 0; long maxSize = BlockSetting.MAX_BLOCK_SIZE - (1 * 1024); var poolItemList = txPool.MainPool.OrderByDescending(t => t.FeeRate).ToList(); var index = 0; while (totalSize < maxSize && index < poolItemList.Count) { var tx = poolItemList[index].Transaction; if (tx != null && transactionMsgs.Where(t => t.Hash == tx.Hash).Count() == 0) { if (txDac.SelectByHash(tx.Hash) == null) { transactionMsgs.Add(tx); totalSize += tx.Size; } else { txPool.RemoveTransaction(tx.Hash); } } else { break; } index++; } var minerAccount = accountDac.SelectDefaultAccount(); if (accountId != null) { var account = accountDac.SelectById(accountId); if (account != null && !string.IsNullOrWhiteSpace(account.PrivateKey)) { minerAccount = account; } } var minerAccountId = minerAccount.Id; BlockMsg newBlockMsg = new BlockMsg(); BlockHeaderMsg headerMsg = new BlockHeaderMsg(); headerMsg.Hash = Base16.Encode(HashHelper.EmptyHash()); headerMsg.GeneratorId = generatorId; newBlockMsg.Header = headerMsg; headerMsg.Height = lastBlockHeight + 1; headerMsg.PreviousBlockHash = lastBlockHash; if (headerMsg.Height == 0) { minerAccountId = BlockSetting.GenesisBlockReceiver; remark = BlockSetting.GenesisBlockRemark; } long totalAmount = 0; long totalFee = 0; foreach (var tx in transactionMsgs) { long totalInputsAmount = 0L; long totalOutputAmount = 0L; foreach (var input in tx.Inputs) { var utxo = outputDac.SelectByHashAndIndex(input.OutputTransactionHash, input.OutputIndex); if (utxo != null) { totalInputsAmount += utxo.Amount; } } foreach (var output in tx.Outputs) { totalOutputAmount += output.Amount; } totalAmount += totalOutputAmount; totalFee += (totalInputsAmount - totalOutputAmount); } //var work = new POW(headerMsg.Height); BlockMsg prevBlockMsg = null; BlockMsg prevStepBlockMsg = null; if (blockEntity != null) { prevBlockMsg = this.convertEntityToBlockMsg(blockEntity); } if (headerMsg.Height >= POC.DIFFIUCLTY_ADJUST_STEP) { prevStepBlockMsg = this.GetBlockMsgByHeight(headerMsg.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1); } var newBlockReward = POC.GetNewBlockReward(headerMsg.Height); headerMsg.Bits = POC.CalculateBaseTarget(headerMsg.Height, prevBlockMsg, prevStepBlockMsg); headerMsg.TotalTransaction = transactionMsgs.Count + 1; var coinbaseTxMsg = new TransactionMsg(); coinbaseTxMsg.Timestamp = Time.EpochTime; coinbaseTxMsg.Locktime = 0; var coinbaseInputMsg = new InputMsg(); coinbaseTxMsg.Inputs.Add(coinbaseInputMsg); coinbaseInputMsg.OutputIndex = 0; coinbaseInputMsg.OutputTransactionHash = Base16.Encode(HashHelper.EmptyHash()); coinbaseInputMsg.UnlockScript = Script.BuildMinerScript(minerName, remark); coinbaseInputMsg.Size = coinbaseInputMsg.UnlockScript.Length; var coinbaseOutputMsg = new OutputMsg(); coinbaseTxMsg.Outputs.Add(coinbaseOutputMsg); coinbaseOutputMsg.Amount = newBlockReward + totalFee; coinbaseOutputMsg.LockScript = Script.BuildLockScipt(minerAccountId); coinbaseOutputMsg.Size = coinbaseOutputMsg.LockScript.Length; coinbaseOutputMsg.Index = 0; coinbaseTxMsg.Hash = coinbaseTxMsg.GetHash(); newBlockMsg.Transactions.Insert(0, coinbaseTxMsg); foreach (var tx in transactionMsgs) { newBlockMsg.Transactions.Add(tx); } headerMsg.PayloadHash = newBlockMsg.GetPayloadHash(); var dsa = ECDsa.ImportPrivateKey(Base16.Decode(minerAccount.PrivateKey)); var signResult = dsa.SingnData(Base16.Decode(headerMsg.PayloadHash)); headerMsg.BlockSignature = Base16.Encode(signResult); headerMsg.BlockSigSize = headerMsg.BlockSignature.Length; headerMsg.TotalTransaction = newBlockMsg.Transactions.Count; return(newBlockMsg); }
public bool VerifyBlock(BlockMsg newBlock) { if (this.exists(newBlock.Header.Hash)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HAS_BEEN_EXISTED); } if (newBlock.Header.Hash != newBlock.Header.GetHash()) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_HASH_ERROR); } var blockComponent = new BlockComponent(); var previousBlock = this.GetBlockMsgByHash(newBlock.Header.PreviousBlockHash); if (newBlock.Header.Height > 0 && previousBlock == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.PREV_BLOCK_NOT_EXISTED); } if ((newBlock.Header.Timestamp > Time.EpochTime && (newBlock.Header.Timestamp - Time.EpochTime) > 2 * 60 * 60 * 1000) || (previousBlock != null && newBlock.Header.Timestamp <= previousBlock.Header.Timestamp)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_TIME_IS_ERROR); } if (newBlock.Serialize().Length > BlockSetting.MAX_BLOCK_SIZE) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIZE_LARGE_THAN_LIMIT); } var txComponent = new TransactionComponent(); var newBlockReward = POC.GetNewBlockReward(newBlock.Header.Height); var prevStepBlock = GetBlockMsgByHeight(newBlock.Header.Height - POC.DIFFIUCLTY_ADJUST_STEP - 1); var minerInfo = string.Empty; if (newBlock.Transactions.Count > 0) { var coinbase = newBlock.Transactions[0]; var totalFee = 0L; minerInfo = Encoding.UTF8.GetString(Base16.Decode(coinbase.Inputs[0].UnlockScript)).Split("`")[0]; if (newBlock.Transactions.Count > 1) { for (int i = 1; i < newBlock.Transactions.Count; i++) { long fee; if (txComponent.VerifyTransaction(newBlock.Transactions[i], out fee)) { totalFee += fee; } else { return(false); } } } if (coinbase.Inputs.Count != 1 || coinbase.Outputs.Count != 1 || coinbase.Inputs[0].OutputTransactionHash != Base16.Encode(HashHelper.EmptyHash())) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_FORMAT_ERROR); } else { var output = coinbase.Outputs[0]; if (output.Amount > BlockSetting.OUTPUT_AMOUNT_MAX) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.OUTPUT_EXCEEDED_THE_LIMIT); } if (!Script.VerifyLockScriptFormat(output.LockScript)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.SCRIPT_FORMAT_ERROR); } if (output.Amount != (totalFee + newBlockReward)) { throw new CommonException(ErrorCode.Engine.Transaction.Verify.COINBASE_OUTPUT_AMOUNT_ERROR); } } } var pool = new MiningPoolComponent().GetMiningPoolByName(minerInfo); if (pool == null) { throw new CommonException(ErrorCode.Engine.Block.Verify.MINING_POOL_NOT_EXISTED); } if (!POC.VerifyBlockSignature(newBlock.Header.PayloadHash, newBlock.Header.BlockSignature, pool.PublicKey)) { throw new CommonException(ErrorCode.Engine.Block.Verify.BLOCK_SIGNATURE_IS_ERROR); } long previousBlockHeight = -1; long previousBlockBits = -1; if (previousBlock != null) { previousBlockHeight = previousBlock.Header.Height; previousBlockBits = previousBlock.Header.Bits; } if (POC.CalculateBaseTarget(newBlock.Header.Height, previousBlock, prevStepBlock) != newBlock.Header.Bits) { throw new CommonException(ErrorCode.Engine.Block.Verify.BITS_IS_WRONG); } var targetResult = POC.CalculateTargetResult(newBlock); if (POC.Verify(newBlock.Header.Bits, targetResult)) { return(true); } else { throw new CommonException(ErrorCode.Engine.Block.Verify.POC_VERIFY_FAIL); } }
public async Task Create(POC poc) { await context1.POCs.InsertOneAsync(poc); }