Ejemplo n.º 1
0
        /// <summary>
        /// try to find "Transfer" event, then add record to db
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="transaction"></param>
        /// <param name="block"></param>
        /// <param name="snapshot"></param>
        /// <returns></returns>
        private bool HasTransfer(NotificationInfo notification, Transaction transaction, Block block, SnapshotView snapshot)
        {
            var assetHash = UInt160.Parse(notification.Contract);
            var asset     = AssetCache.GetAssetInfo(assetHash, snapshot);

            if (asset == null)
            {
                //not nep5 asset
                return(false);
            }
            var notify = JStackItem.FromJson(notification.State);

            if (!(notify.Value is IList <JStackItem> notifyArray) || notifyArray.Count < 4)
            {
                return(false);
            }
            if (!"transfer".Equals(notifyArray[0].ValueString, StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }
            var from = notifyArray[1].Value as byte[];
            var to   = notifyArray[2].Value as byte[];

            if (from == null && to == null)
            {
                return(false);
            }
            if (!ConvertBigInteger(notifyArray[3], out var amount))
            {
                return(false);
            }

            var record = new TransferInfo
            {
                BlockHeight = block.Index,
                From        = from == null ? null : new UInt160(from),
                To          = to == null ? null : new UInt160(to),
                Asset       = asset.Asset,
                Amount      = amount,
                TxId        = transaction.Hash,
                TimeStamp   = block.Timestamp,
                AssetInfo   = asset,
            };

            _db.AddTransfer(record);

            if (record.From != null)
            {
                var fromBalance = record.From.GetBalanceOf(assetHash, snapshot);
                _db.UpdateBalance(record.From, asset, fromBalance.Value, snapshot.Height);
            }

            if (record.To != null && record.To != record.From)
            {
                var toBalance = record.To.GetBalanceOf(assetHash, snapshot);
                _db.UpdateBalance(record.To, asset, toBalance.Value, snapshot.Height);
            }
            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// query transaction info
        /// </summary>
        /// <param name="txId"></param>
        /// <returns></returns>
        public async Task <object> GetTransaction(UInt256 txId)
        {
            var snapshot    = Helpers.GetDefaultSnapshot();
            var transaction = snapshot.GetTransaction(txId);

            if (transaction == null)
            {
                return(Error(ErrorCode.TxIdNotFound));
            }

            var model = new TransactionModel(transaction);

            var txState = snapshot.GetTransactionState(txId);

            if (txState != null)
            {
                Header header = snapshot.GetHeader(txState.BlockIndex);
                model.BlockHash     = header.Hash;
                model.BlockHeight   = txState.BlockIndex;
                model.Timestamp     = header.Timestamp;
                model.Confirmations = snapshot.GetHeight() - header.Index + 1;
            }
            using var db = new TrackDB();
            var trans = db.QueryTransfers(new TransferFilter()
            {
                TxIds = new List <UInt256>()
                {
                    txId
                }, PageSize = int.MaxValue
            }).List;

            model.Transfers = trans.Select(tx => tx.ToTransferModel()).ToList();

            var executeResult = db.GetExecuteLog(txId);

            if (executeResult?.Notifications.NotEmpty() == true)
            {
                model.Notifies.AddRange(
                    executeResult.Notifications.Select(n => new NotifyModel()
                {
                    Contract  = n.Contract,
                    EventName = n.EventName,
                    State     = JStackItem.FromJson(n.State),
                }));
            }
            return(model);
        }
        /// <summary>
        /// query transaction info
        /// </summary>
        /// <param name="txId"></param>
        /// <returns></returns>
        public async Task <object> GetTransaction(UInt256 txId)
        {
            var transaction = Blockchain.Singleton.GetTransaction(txId);

            if (transaction == null)
            {
                return(Error(ErrorCode.TxIdNotFound));
            }

            var model = new TransactionModel(transaction);

            TransactionState txState = Blockchain.Singleton.View.Transactions.TryGet(txId);

            if (txState != null)
            {
                Header header = Blockchain.Singleton.GetHeader(txState.BlockIndex);
                model.BlockHash     = header.Hash;
                model.BlockHeight   = txState.BlockIndex;
                model.Timestamp     = header.Timestamp;
                model.Confirmations = Blockchain.Singleton.Height - header.Index + 1;
            }
            using var db = new TrackDB();
            var trans = db.FindTransfer(new TransferFilter()
            {
                TxIds = new List <UInt256>()
                {
                    txId
                }, PageSize = int.MaxValue
            }).List;

            model.Transfers = trans.Select(tx => tx.ToTransferModel()).ToList();

            var executeResult = db.GetExecuteLog(txId);

            if (executeResult?.Notifications.NotEmpty() == true)
            {
                model.Notifies.AddRange(
                    executeResult.Notifications.Select(n => new NotifyModel()
                {
                    Contract = UInt160.Parse(n.Contract),
                    State    = JStackItem.FromJson(n.State),
                }));
            }
            return(model);
        }
Ejemplo n.º 4
0
        public async Task <object> InvokeContract(InvokeContractParameterModel para)
        {
            if (CurrentWallet == null)
            {
                return(Error(ErrorCode.WalletNotOpen));
            }
            if (para.ContractHash == null || para.Method.IsNull())
            {
                return(Error(ErrorCode.ParameterIsNull));
            }
            using var snapshot = Blockchain.Singleton.GetSnapshot();
            var contract = snapshot.Contracts.TryGet(para.ContractHash);

            if (contract == null)
            {
                return(Error(ErrorCode.UnknownContract));
            }

            ContractParameter[] contractParameters = null;
            try
            {
                contractParameters = para.Parameters?.Select(p =>
                {
                    return(ContractParameter.FromJson(p));
                    //var parameterValue = new ContractParameter(p.Type);
                    //parameterValue.SetValue(p.Value);
                    //return parameterValue;
                }).ToArray();
            }
            catch (Exception e)
            {
                return(Error(ErrorCode.InvalidPara));
            }

            var signers = new List <Cosigner>();

            if (para.Cosigners.NotEmpty())
            {
                signers.AddRange(para.Cosigners.Select(s => new Cosigner()
                {
                    Account = s.Account, Scopes = s.Scopes
                }));
            }

            Transaction tx = null;

            using ScriptBuilder sb = new ScriptBuilder();
            sb.EmitAppCall(para.ContractHash, para.Method, contractParameters);

            try
            {
                tx = CurrentWallet.InitTransaction(sb.ToArray(), signers.ToArray());
            }
            catch (InvalidOperationException)
            {
                return(Error(ErrorCode.EngineFault));
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Insufficient GAS"))
                {
                    return(Error(ErrorCode.GasNotEnough));
                }
                throw;
            }

            var(signSuccess, context) = CurrentWallet.TrySignTx(tx);
            if (!signSuccess)
            {
                return(Error(ErrorCode.SignFail, context.SafeSerialize()));
            }
            var result = new InvokeResultModel();

            using ApplicationEngine engine = ApplicationEngine.Run(tx.Script, tx, testMode: true);
            result.VmState     = engine.State;
            result.GasConsumed = new BigDecimal(tx.SystemFee, NativeContract.GAS.Decimals);
            result.ResultStack = engine.ResultStack.Select(p => JStackItem.FromJson(p.ToParameter().ToJson())).ToList();
            if (engine.State.HasFlag(VMState.FAULT))
            {
                return(Error(ErrorCode.EngineFault));
            }
            if (!para.SendTx)
            {
                return(result);
            }
            await tx.Broadcast();

            result.TxId = tx.Hash;
            return(result);
        }
Ejemplo n.º 5
0
        public async Task <object> InvokeContract(InvokeContractParameterModel para)
        {
            if (CurrentWallet == null)
            {
                return(Error(ErrorCode.WalletNotOpen));
            }
            if (para.ContractHash == null || para.Method.IsNull())
            {
                return(Error(ErrorCode.ParameterIsNull));
            }
            var contract = para.ContractHash.GetContract();

            if (contract == null)
            {
                return(Error(ErrorCode.UnknownContract));
            }

            ContractParameter[] contractParameters = null;
            try
            {
                contractParameters = para.Parameters?.Select(JsonToContractParameter).ToArray();
            }
            catch (Exception e)
            {
                return(Error(ErrorCode.InvalidPara));
            }

            var signers = new List <Signer>();

            if (para.Cosigners.NotEmpty())
            {
                signers.AddRange(para.Cosigners.Select(s => new Signer()
                {
                    Account = s.Account, Scopes = s.Scopes, AllowedContracts = new UInt160[0]
                }));
            }

            Transaction tx = null;

            using ScriptBuilder sb = new ScriptBuilder();
            sb.EmitDynamicCall(para.ContractHash, para.Method, contractParameters);

            try
            {
                tx = CurrentWallet.InitTransaction(sb.ToArray(), null, signers.ToArray());
            }
            catch (InvalidOperationException ex)
            {
                return(Error(ErrorCode.EngineFault, $"{ex.Message}\r\n   InnerError:{ex.InnerException}"));
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Insufficient GAS"))
                {
                    return(Error(ErrorCode.GasNotEnough));
                }
                throw;
            }

            var(signSuccess, context) = CurrentWallet.TrySignTx(tx);
            if (!signSuccess)
            {
                return(Error(ErrorCode.SignFail, context.SafeSerialize()));
            }
            var result = new InvokeResultModel();

            using ApplicationEngine engine = tx.Script.RunTestMode(null, tx);
            result.VmState       = engine.State;
            result.GasConsumed   = new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals);
            result.ResultStack   = engine.ResultStack.Select(p => JStackItem.FromJson(p.ToContractParameter().ToJson())).ToList();
            result.Notifications = engine.Notifications?.Select(ConvertToEventModel).ToList();
            if (engine.State.HasFlag(VMState.FAULT))
            {
                return(Error(ErrorCode.EngineFault));
            }
            if (!para.SendTx)
            {
                return(result);
            }
            await tx.Broadcast();

            result.TxId = tx.Hash;
            return(result);
        }