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);
            }
        }
Exemplo n.º 2
0
        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);
        }