private List<Subsidy> GetNewSubsidies() { int lastKnownBlockHeight = 0; // HashSet<string> p2poolAddresses = null; Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { lastKnownBlockHeight = (from b in db.Blocks orderby b.BlockHeight descending select b.BlockHeight).Take(1).FirstOrDefault(); //var p2poolAddressesQuery = (from u in db.Users // select u.Address).Distinct(); //p2poolAddresses = new HashSet<string>(p2poolAddressesQuery); } }); foreach (var backend in _backends) { try { //return backend.GetNewSubsidies(lastKnownBlockHeight, p2poolAddresses); } catch { //absorb } } return new List<Subsidy>(); }
private List<Block> GetNewBlocks() { int lastKnownBlockHeight = 0; string[] lastKnownBlockHashes = null; HashSet<string> knownTxHashes = null; Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { lastKnownBlockHeight = (from b in db.Blocks orderby b.BlockHeight descending select b.BlockHeight).Take(1).FirstOrDefault(); lastKnownBlockHashes = (from b in db.Blocks where b.BlockHeight == lastKnownBlockHeight select b.Id).ToArray(); knownTxHashes = new HashSet<string>(from b in db.Blocks where b.IsP2Pool || b.IsFalseP2Pool select b.GenerationTxHash); } }); IEnumerable<Block> newBlocks = null; foreach (var backend in _backends) { try { var someNewBlocks = backend.GetNewBlocks(lastKnownBlockHeight, lastKnownBlockHashes, knownTxHashes); if (newBlocks == null) { newBlocks = someNewBlocks; } else { newBlocks = newBlocks.Union(someNewBlocks, new BlockEqualityComparer()); } knownTxHashes.UnionWith(from b in someNewBlocks select b.GenerationTxHash); } catch { //absorb } } return new List<Block>(newBlocks ?? new Block[] { }); }
public ActionResult Stats(long? from) { Stopwatch timer = new Stopwatch(); Debug.WriteLine("Starting stats update, from = {0}", from); timer.Start(); return Retry.ExecuteAction<ActionResult>(() => { using (P2PoolDb db = new P2PoolDb()) { int cutoff = 0; var statsQuery = db.Stats.AsQueryable(); if (from.HasValue) { cutoff = (int)from.Value / 1000; statsQuery = statsQuery.Where(s => s.Timestamp > cutoff); } var ratesQuery = (from s in statsQuery group s by Math.Floor(s.Timestamp / 7200m) into grouped select new { Timestamp = grouped.Key * 7200000, Rate = grouped.Average(x => x.Rate), Users = grouped.Max(x => x.Users) }); if (from.HasValue) { ratesQuery = ratesQuery.Where(x => x.Timestamp > from.Value); } var rates = ratesQuery.ToList(); if (rates.Count == 0) { return Json(new { rates = new int[] { }, users = new int[] { } }, JsonRequestBehavior.AllowGet); } var ratesArray = (from r in rates orderby r.Timestamp select new List<object> { (long)r.Timestamp, Math.Round((double)r.Rate, 1) }).ToList(); var users = (from r in rates orderby r.Timestamp select new List<object> { (long)r.Timestamp, (int)r.Users }).ToList(); var maxRate = (from s in db.Stats select s.Rate).Max(); var maxUsers = (from s in db.Stats select s.Users).Max(); var result = new { rates = ratesArray, users = users.ToList(), maxRate = maxRate, maxUsers = maxUsers, }; string json = JsonConvert.SerializeObject(result); timer.Stop(); Debug.WriteLine("..End stats update, from = {0}, time = {1}", from, timer.ElapsedMilliseconds / 1000m); return Content(json, "application/json"); } }); }
private List<Block> GetBlocks() { Stopwatch timer = new Stopwatch(); Debug.WriteLine("Starting blocks update"); timer.Start(); return Retry.ExecuteAction<List<Block>>(() => { using (P2PoolDb db = new P2PoolDb()) { var dbBlockCount = (from b in db.Blocks where b.IsP2Pool select b).Count(); if (DateTime.Now < _blocksExpire && _blocks != null && dbBlockCount == _blocks.Count) { var lastBlock = (from b in db.Blocks where b.IsP2Pool orderby b.BlockHeight descending select b).First(); if (lastBlock.Id == _blocks[0].Id && lastBlock.IsOrphaned == _blocks[0].IsOrphaned) { return _blocks; } } var blocks = (from b in db.Blocks where b.IsP2Pool orderby b.BlockHeight, b.Timestamp select b).ToList(); try { //build hashrate list List<Stat> stats = (from s in db.Stats orderby s.Timestamp select s).ToList(); Block lastBlock = null; foreach (var block in blocks) { if (lastBlock != null) { block.RoundDuration = block.Timestamp - lastBlock.Timestamp; decimal averageRateBetweenBlocks = GetAverageHashBetweenTimes(lastBlock.Timestamp, block.Timestamp, stats) * 1000000000; decimal difficulty = block.Difficulty; block.ExpectedDuration = (int)(difficulty * 4294967296 / averageRateBetweenBlocks); block.ActualShares = (long)((block.RoundDuration * averageRateBetweenBlocks) / 4294967296); block.ExpectedShares = (long)difficulty; } lastBlock = block; } blocks.Sort(new Comparison<Block>((a, b) => { var result = b.BlockHeight.CompareTo(a.BlockHeight); if (result == 0) { result = b.Timestamp.CompareTo(a.Timestamp); } return result; })); _blocks = blocks; _blocksExpire = DateTime.Now.AddHours(2); return blocks; } catch { return _blocks; } finally { timer.Stop(); Debug.WriteLine("..End blocks update, time = {0}", timer.ElapsedMilliseconds / 1000m); } } }); }
public ActionResult Users() { return Retry.ExecuteAction<ActionResult>(() => { using (P2PoolDb db = new P2PoolDb()) { int cutoff = (int)(DateTime.UtcNow.AddHours(-24) - new DateTime(1970, 1, 1)).TotalSeconds; var rawUsers = (from u in db.Users where u.Timestamp > cutoff select u).ToList(); decimal sum = rawUsers.Sum(u => u.Portion); List<Stat> stats = (from s in db.Stats where s.Timestamp > (cutoff - 86400) select s).ToList(); decimal totalHashrate = GetAverageHashBetweenTimes(cutoff, cutoff + 86400, stats); var response = (from u in rawUsers group u by u.Address into g select new { Address = g.Key, Hashrate = Math.Round(totalHashrate * (g.Sum(u => u.Portion) / sum) * 1000, 0) }) .OrderByDescending(u => u.Hashrate).Select(u => new { Address = u.Address, Hashrate = u.Hashrate.ToString("#,0 MH/s") }); return Json(response, JsonRequestBehavior.AllowGet); } }); }
public ActionResult Donations() { return Retry.ExecuteAction<ActionResult>(() => { using (P2PoolDb db = new P2PoolDb()) { var response = (from s in db.Subsidies orderby s.BlockHeight descending select s).ToList(); return Json(response, JsonRequestBehavior.AllowGet); } }); }
public ActionResult Payouts() { return Retry.ExecuteAction<ActionResult>(() => { using (P2PoolDb db = new P2PoolDb()) { string payoutsJson = db.CurrentPayouts.Find(1).Payouts; var payouts = JObject.Parse(payoutsJson); var response = (from a in (from p in payouts.Properties() select new { Address = P2PHelper.ExtractAddress(p.Name) ?? "Unknown", Payment = (decimal)p.Value }) group a by a.Address into g select new { Address = g.Key, Payment = g.Sum(a => a.Payment) }) .OrderByDescending(p => p.Payment).ToList(); return Json(response, JsonRequestBehavior.AllowGet); } }); }
public void UpdateDatabase() { try { //look for subsidies before we add new blocks because we depend on lastKnowBlockHeight to know where to start looking var subsidies = GetNewSubsidies(); if (subsidies.Count > 0) { Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { foreach (var subsidy in subsidies) { var existingSubsidy = db.Subsidies.Find(subsidy.TxHash); if (existingSubsidy == null) { Log(string.Format("Adding subsidy of {0} BTC, {1}", subsidy.Amount, subsidy.TxHash)); db.Subsidies.Add(subsidy); } else if (existingSubsidy.BlockHeight != subsidy.BlockHeight || existingSubsidy.BlockHash != subsidy.BlockHash) { Log(string.Format("Updating subsidy of {0} BTC, {1}", subsidy.Amount, subsidy.TxHash)); existingSubsidy.BlockHash = subsidy.BlockHash; existingSubsidy.BlockHeight = subsidy.BlockHeight; } db.SaveChanges(); } } }); } var blocks = GetNewBlocks(); if (blocks.Count > 0) { Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { foreach (var block in blocks) { var existingBlock = db.Blocks.Find(block.Id); if (existingBlock == null) { Log(string.Format("Adding block {0}, {1}{2}", block.BlockHeight, block.Id, block.IsP2Pool ? " (p2pool)" : "")); db.Blocks.Add(block); } else { Log(string.Format("Updating block {0}, {1}{2}", block.BlockHeight, block.Id, block.IsP2Pool ? " (p2pool)" : "")); existingBlock.BlockHeight = block.BlockHeight; existingBlock.Difficulty = block.Difficulty; existingBlock.GenerationTxHash = block.GenerationTxHash; existingBlock.IsOrphaned = block.IsOrphaned; existingBlock.IsP2Pool = block.IsP2Pool; existingBlock.PrevBlock = block.PrevBlock; existingBlock.Timestamp = block.Timestamp; } db.SaveChanges(); } //the following logic is too simplistic and only finds orphaned blocks if they are immediatly orphaned (vs a race between to candidate chains that lasts more than 1 block) // this clears the orphaned flag from any blocks that now have a later block pointing at them //db.Database.ExecuteSqlCommand("update p2pool_Blocks set isorphaned=0 where isorphaned=1 and exists (select * from p2pool_Blocks as b2 where b2.PrevBlock = p2pool_Blocks.Id)"); // this sets the orphaned flag for any blocks that aren't pointed at by some later block db.Database.ExecuteSqlCommand("update p2pool_Blocks set isorphaned=1 where blockheight < (select max(blockheight) from p2pool_Blocks) and not exists (select * from p2pool_Blocks as b2 where b2.PrevBlock = p2pool_Blocks.Id)"); } }); } } catch (Exception ex) { Log("UpdateDatabase: " + ex.Message); } }
public void UpdateStats() { try { int timestamp = DateTime.UtcNow.ToUnixTime(); int remainder = timestamp % 300; timestamp -= remainder; Log(string.Format("Updating stats for timestamp {0}", timestamp)); IEnumerable<string> servers = null; bool updatedData = false; P2PWebClient client = new P2PWebClient(); client.RequestTimeout = 3000; Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { var existingUsersCount = (from u in db.Users where u.Timestamp == timestamp select u.Address).Count(); if (existingUsersCount == 0) { JObject users = null; if (servers == null) { servers = GetServers(); } foreach (var server in servers) { if (string.IsNullOrWhiteSpace(server)) { continue; } try { var baseUrl = new Uri(server.Trim()); users = JObject.Parse(client.DownloadString(new Uri(baseUrl, "/users"))); Log(string.Format(" Stats: Retrived users from {0}", server)); break; } catch (Exception ex) { Log(" Stats: " + ex.Message); } } if (users == null) { return; } Dictionary<string, decimal> addresses = new Dictionary<string, decimal>(); foreach (var userEntry in users.Properties()) { string address = P2PHelper.ExtractAddress(userEntry.Name) ?? "Unknown"; if (address != null) { decimal portion = 0; if (addresses.ContainsKey(address)) { portion += addresses[address]; } portion += (decimal)userEntry.Value; addresses[address] = portion; } } foreach (var item in addresses) { User user = new User() { Timestamp = timestamp, Address = item.Key, Portion = item.Value }; db.Users.Add(user); } db.SaveChanges(); updatedData = true; Log(string.Format(" Stats: Added {0} users", addresses.Count)); } } }); Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { Stat entry = db.Stats.Find(timestamp); if (entry == null) { decimal rate = -1; if (servers == null) { servers = GetServers(); } foreach (var server in servers) { if (string.IsNullOrWhiteSpace(server)) { continue; } try { var baseUrl = new Uri(server.Trim()); rate = decimal.Parse(client.DownloadString(new Uri(baseUrl, "/rate"))) / 1000000000m; Log(string.Format(" Stats: Retrived rate from {0}", server)); break; } catch (Exception ex) { Log(" Stats: " + ex.Message); } } if (rate == -1) { return; } int userCount; userCount = db.Database.SqlQuery<int>("select count (distinct address) from p2pool_Users where timestamp >= @start and timestamp <= @end", new SqlParameter("start", timestamp - 86400), new SqlParameter("end", timestamp)).First(); entry = new Stat { Timestamp = timestamp, Rate = rate, Users = userCount }; db.Stats.Add(entry); db.SaveChanges(); updatedData = true; Log(string.Format(" Stats: Saved new rate: {0}", rate)); } } }); if (updatedData) { Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { CurrentPayouts entry = db.CurrentPayouts.Find(1); if (entry != null) { JObject payouts = null; if (servers == null) { servers = GetServers(); } foreach (var server in servers) { if (string.IsNullOrWhiteSpace(server)) { continue; } try { var baseUrl = new Uri(server.Trim()); payouts = JObject.Parse(client.DownloadString(new Uri(baseUrl, "/current_payouts"))); Log(string.Format(" Stats: Retrived payouts from {0}", server)); break; } catch (Exception ex) { Log(" Stats: " + ex.Message); } } if (payouts == null) { return; } entry.Payouts = payouts.ToString(); entry.Updated = timestamp; db.SaveChanges(); Log(" Stats: Saved updated payouts"); } } }); //cleanup old user stats Retry.ExecuteAction(() => { using (P2PoolDb db = new P2PoolDb()) { // delete all the specific user stats older than 3 days var result = db.Database.ExecuteSqlCommand("delete from p2pool_Users where [Timestamp] < @cutoff", new SqlParameter("cutoff", timestamp - 259200)); Log(string.Format(" Stats: Deleted old user rows", result)); } }); } } catch (Exception ex) { Log(" Stats: UpdateStats Exception: " + ex.Message); } }