/// <inheritdoc /> public IContractInvocationResult InvokeConstructor(IReadOnlyList <object> parameters) { // If it's a constructor we need to append the ISmartContractState to the start of the parameters array object[] invokeParams = { this.State }; if (parameters != null) { invokeParams = invokeParams.Concat(parameters).ToArray(); } Type[] types = invokeParams.Select(p => p.GetType()).ToArray(); ConstructorInfo methodToInvoke = this.Type.GetConstructor(types); if (methodToInvoke == null) { return(ContractInvocationResult.Failure(ContractInvocationErrorType.MethodDoesNotExist)); } IContractInvocationResult result = this.InvokeInternal(methodToInvoke, invokeParams); this.initialized = result.IsSuccess; return(result); }
private IContractInvocationResult InvokeReceiveHandler() { // Handles the scenario where no receive was defined, but it is attempted to be invoked anyway. // This could occur if a method invocation is directly made to the receive via a transaction. if (this.ReceiveHandler == null) { return(ContractInvocationResult.Failure(ContractInvocationErrorType.MethodDoesNotExist)); } this.EnsureInitialized(); return(this.InvokeInternal(this.ReceiveHandler, null)); }
/// <inheritdoc /> public IContractInvocationResult Invoke(MethodCall call) { if (call.IsReceiveHandlerCall) { return(this.InvokeReceiveHandler()); } object[] invokeParams = call.Parameters?.ToArray() ?? new object[0]; if (invokeParams.Any(p => p == null)) { // Do not support binding of null parameter values. return(ContractInvocationResult.Failure(ContractInvocationErrorType.ParameterTypesDontMatch)); } Type[] types = invokeParams.Select(p => p.GetType()).ToArray(); MethodInfo methodToInvoke = this.Type.GetMethod(call.Name, types); if (methodToInvoke == null) { // Check if a method with this name exists but the args are incorrect var methodExists = this.Type.GetMethods().Any(m => m.Name == call.Name); if (!methodExists) { return(ContractInvocationResult.Failure(ContractInvocationErrorType.MethodDoesNotExist)); } return(ContractInvocationResult.Failure(ContractInvocationErrorType.ParameterTypesDontMatch)); } // This should not happen without setting the appropriate binding flags if (methodToInvoke.IsConstructor) { return(ContractInvocationResult.Failure(ContractInvocationErrorType.MethodIsConstructor)); } // This should not happen without setting the appropriate binding flags if (methodToInvoke.IsPrivate) { return(ContractInvocationResult.Failure(ContractInvocationErrorType.MethodIsPrivate)); } this.EnsureInitialized(); return(this.InvokeInternal(methodToInvoke, invokeParams)); }
/// <summary> /// Shared internal logic for invoking a method. /// </summary> private IContractInvocationResult InvokeInternal(MethodBase method, object[] parameters) { try { object result = method.Invoke(this.instance, parameters); return(ContractInvocationResult.Success(result)); } catch (TargetParameterCountException parameterException) { // Parameter count incorrect // This should not happen return(ContractInvocationResult.Failure(ContractInvocationErrorType.ParameterCountIncorrect)); } catch (ArgumentException argumentException) { // Parameters do not match // This should not happen return(ContractInvocationResult.Failure(ContractInvocationErrorType.ParameterTypesDontMatch)); } catch (TargetInvocationException targetException) when(!(targetException.InnerException is OutOfGasException) && !(targetException.InnerException is MemoryConsumptionException)) { // Method threw an exception that was not an OutOfGasException or a MemoryConsumptionException // TODO: OutofGas and MemoryConsumption exceptions should inherit from same base 'ResourceTrackingException' // which can be tracked here. return(ContractInvocationResult.ExecutionFailure(ContractInvocationErrorType.MethodThrewException, targetException.InnerException)); } catch (TargetInvocationException targetException) when(targetException.InnerException is OutOfGasException) { // Method threw an OutOfGasException return(ContractInvocationResult.ExecutionFailure(ContractInvocationErrorType.OutOfGas, targetException.InnerException)); } catch (TargetInvocationException targetException) when(targetException.InnerException is MemoryConsumptionException) { // Method threw a MemoryConsumptionException return(ContractInvocationResult.ExecutionFailure(ContractInvocationErrorType.OverMemoryLimit, targetException.InnerException)); } catch (Exception e) { // Other unexpected exceptions return(ContractInvocationResult.ExecutionFailure(ContractInvocationErrorType.Exception, e)); } }