Beispiel #1
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);
        }
Beispiel #2
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);
        }