public async Task <ActionResult> GetBlockByHash(string hash, int noTxList = 1) { if (!Validations.IsValidHash(hash)) { return(BadRequest(hash + " is not a valid block hash")); } Utils.CheckIfChainIsFresh(chain_, config_.AcceptStaleRequests); string key = "block" + noTxList + hash; if (memoryCache_.TryGetValue(key, out JsonResult cachedBlockJson)) { return(cachedBlockJson); } ; var binaryHash = Binary.HexStringToByteArray(hash); using (DisposableApiCallResult <GetBlockHeaderByHashTxSizeResult> getBlockResult = await chain_.FetchBlockHeaderByHashTxSizesAsync(binaryHash)) { Utils.CheckBitprimApiErrorCode(getBlockResult.ErrorCode, "FetchBlockHeaderByHashTxSizesAsync(" + hash + ") failed, check error log"); var getLastHeightResult = await chain_.FetchLastHeightAsync(); Utils.CheckBitprimApiErrorCode(getLastHeightResult.ErrorCode, "FetchLastHeightAsync() failed, check error log"); var blockHeight = getBlockResult.Result.Header.BlockHeight; ApiCallResult <GetBlockHashTimestampResult> getNextBlockResult = null; if (blockHeight != getLastHeightResult.Result) { getNextBlockResult = await chain_.FetchBlockByHeightHashTimestampAsync(blockHeight + 1); Utils.CheckBitprimApiErrorCode(getNextBlockResult.ErrorCode, "FetchBlockByHeightHashTimestampAsync(" + blockHeight + 1 + ") failed, check error log"); } decimal blockReward; PoolInfo poolInfo; using (DisposableApiCallResult <GetTxDataResult> coinbase = await chain_.FetchTransactionAsync(getBlockResult.Result.TransactionHashes[0], true)) { Utils.CheckBitprimApiErrorCode(coinbase.ErrorCode, "FetchTransactionAsync(" + getBlockResult.Result.TransactionHashes[0] + ") failed, check error log"); blockReward = Utils.SatoshisToCoinUnits(coinbase.Result.Tx.TotalOutputValue); poolInfo = poolsInfo_.GetPoolInfo(coinbase.Result.Tx); } JsonResult blockJson = Json(BlockToJSON ( getBlockResult.Result.Header.BlockData, blockHeight, getBlockResult.Result.TransactionHashes, blockReward, getLastHeightResult.Result, getNextBlockResult?.Result.BlockHash, getBlockResult.Result.SerializedBlockSize, poolInfo, noTxList == 0) ); memoryCache_.Set(key, blockJson, new MemoryCacheEntryOptions { Size = Constants.Cache.BLOCK_CACHE_ENTRY_SIZE }); return(blockJson); } }
private async Task <object> DoGetSyncStatus() { var getLastHeightResult = await chain_.FetchLastHeightAsync(); Utils.CheckBitprimApiErrorCode(getLastHeightResult.ErrorCode, "GetLastHeight() failed"); var currentHeight = getLastHeightResult.Result; if (!memoryCache_.TryGetValue(Constants.Cache.LAST_BLOCK_TIMESTAMP, out long lastBlockTimestamp)) { var getLastBlockResult = await chain_.FetchBlockByHeightHashTimestampAsync(currentHeight); Utils.CheckBitprimApiErrorCode(getLastBlockResult.ErrorCode, "FetchBlockByHeightAsync(" + currentHeight + ") failed, check error log"); lastBlockTimestamp = new DateTimeOffset(getLastBlockResult.Result.BlockTimestamp).ToUnixTimeSeconds(); memoryCache_.Set(Constants.Cache.LAST_BLOCK_TIMESTAMP, lastBlockTimestamp, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = Constants.Cache.BLOCK_TIMESTAMP_MAX_AGE, Size = Constants.Cache.TIMESTAMP_ENTRY_SIZE }); } if (!memoryCache_.TryGetValue(Constants.Cache.FIRST_BLOCK_TIMESTAMP, out long firstBlockTimestamp)) { var getFirstBlockResult = await chain_.FetchBlockByHeightHashTimestampAsync(0); Utils.CheckBitprimApiErrorCode(getFirstBlockResult.ErrorCode, "FetchBlockByHeightHashTimestampAsync(0) failed, check error log"); firstBlockTimestamp = new DateTimeOffset(getFirstBlockResult.Result.BlockTimestamp).ToUnixTimeSeconds(); memoryCache_.Set(Constants.Cache.FIRST_BLOCK_TIMESTAMP, firstBlockTimestamp, new MemoryCacheEntryOptions { Size = Constants.Cache.TIMESTAMP_ENTRY_SIZE }); } var nowTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var lastBlockAge = nowTimestamp - lastBlockTimestamp; bool synced = lastBlockAge < config_.BlockchainStalenessThreshold; dynamic syncStatus = new ExpandoObject(); syncStatus.status = synced ? "finished" : "synchronizing"; syncStatus.blockChainHeight = currentHeight; syncStatus.syncPercentage = synced? 100 : Math.Min(Math.Round((double)(lastBlockTimestamp - firstBlockTimestamp) / (double)(nowTimestamp - firstBlockTimestamp) * 100.0, 2), 100); syncStatus.height = currentHeight; syncStatus.error = null; syncStatus.type = config_.NodeType; return(syncStatus); }