private async Task <SmartContractRegistrationCache> GetSmartContractRegistrationCacheFromLibCache(
            IChainContext chainContext, Address address)
        {
            if (_smartContractRegistrationCacheProvider.TryGetLibCache(address,
                                                                       out var smartContractRegistrationCache))
            {
                return(smartContractRegistrationCache);
            }

            if (chainContext.BlockHeight > 0 && _initLibBlockHeight == 0)
            {
                var chain = await _blockchainService.GetChainAsync();

                _initLibBlockHash   = chain.LastIrreversibleBlockHash;
                _initLibBlockHeight = chain.LastIrreversibleBlockHeight;
            }

            //Use lib chain context to set lib cache. Genesis block need to execute with state cache
            var context = new ChainContext
            {
                BlockHash   = _initLibBlockHash,
                BlockHeight = _initLibBlockHeight,
                StateCache  = chainContext.BlockHeight == 0 ? chainContext.StateCache : null
            };

            if (!_deployedContractAddressProvider.CheckContractAddress(context, address))
            {
                return(null);
            }
            SmartContractRegistration smartContractRegistration;

            if (address == _defaultContractZeroCodeProvider.ContractZeroAddress)
            {
                smartContractRegistration = _defaultContractZeroCodeProvider.DefaultContractZeroRegistration;
                if (context.BlockHeight > Constants.GenesisBlockHeight)
                {
                    var executive = await GetExecutiveAsync(smartContractRegistration);

                    smartContractRegistration =
                        await GetSmartContractRegistrationFromZeroAsync(executive, context, address);
                }
            }
            else
            {
                smartContractRegistration = await GetSmartContractRegistrationFromZeroAsync(context, address);
            }

            smartContractRegistrationCache = new SmartContractRegistrationCache
            {
                SmartContractRegistration = smartContractRegistration,
                BlockHash   = context.BlockHash,
                BlockHeight = context.BlockHeight,
                Address     = address
            };
            _smartContractRegistrationCacheProvider.SetLibCache(address, smartContractRegistrationCache);
            return(smartContractRegistrationCache);
        }
        public async Task <bool> ValidateTransactionAsync(Transaction transaction)
        {
            var chain = await _blockchainService.GetChainAsync();

            var chainContext = new ChainContext
            {
                BlockHash   = chain.BestChainHash,
                BlockHeight = chain.BestChainHeight
            };

            if (_deployedContractAddressProvider.CheckContractAddress(chainContext, transaction.To))
            {
                return(true);
            }

            Logger.LogWarning($"Invalid contract address: {transaction}");
            return(false);
        }
        public async Task <bool> ValidateTransactionAsync(Transaction transaction)
        {
            // Skip if this is a system transaction.
            if (_feeExemptionService.IsFree(transaction))
            {
                return(true);
            }

            var chain = await _blockchainService.GetChainAsync();

            var chainContext = new ChainContext
            {
                BlockHash   = chain.BestChainHash,
                BlockHeight = chain.BestChainHeight
            };

            // Skip if the sender is a contract.
            if (_deployedContractAddressProvider.CheckContractAddress(chainContext, transaction.From))
            {
                return(true);
            }

            // Skip this validation at the very beginning of current chain.
            if (chain.LastIrreversibleBlockHeight == Constants.GenesisBlockHeight)
            {
                return(true);
            }

            var tokenStub = _tokenContractReaderFactory.Create(chainContext);
            var balance   = (await tokenStub.GetBalance.CallAsync(new GetBalanceInput
            {
                Owner = transaction.From,
                Symbol = await _primaryTokenSymbolProvider.GetPrimaryTokenSymbol()
            }))?.Balance;

            // balance == null means token contract hasn't deployed.
            if (balance == null || balance > 0)
            {
                return(true);
            }

            Logger.LogWarning($"Empty balance of tx from address: {transaction}");
            return(false);
        }