Exemplo n.º 1
0
        /// <summary>
        /// Loads the contract bytecode and returns an <see cref="IContract"/> representing an uninitialized contract instance.
        /// </summary>
        private Result <IContract> Load(
            ContractByteCode byteCode,
            string typeName,
            uint160 address,
            ISmartContractState contractState)
        {
            Result <IContractAssembly> assemblyLoadResult = this.assemblyLoader.Load(byteCode);

            if (!assemblyLoadResult.IsSuccess)
            {
                return(Result.Fail <IContract>(assemblyLoadResult.Error));
            }

            IContractAssembly contractAssembly = assemblyLoadResult.Value;

            Type type = contractAssembly.GetType(typeName);

            if (type == null)
            {
                return(Result.Fail <IContract>("Type not found!"));
            }

            IContract contract = Contract.CreateUninitialized(type, contractState, address);

            return(Result.Ok(contract));
        }
        private Result <ContractByteCode> GetByteCode(IContractModuleDefinition moduleDefinition)
        {
            try
            {
                ContractByteCode code = moduleDefinition.ToByteCode();

                return(Result.Ok(code));
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred: {0}", e.ToString());
                this.logger.LogTrace("(-)[CONTRACT_TOBYTECODE_FAILED]");

                return(Result.Fail <ContractByteCode>("Exception occurred while serializing module"));
            }
        }
        /// <summary>
        /// Loads the contract bytecode and returns an <see cref="IContract"/> representing an uninitialized contract instance.
        /// </summary>
        private Result <IContract> Load(
            ContractByteCode byteCode,
            string typeName,
            uint160 address,
            ISmartContractState contractState)
        {
            Result <IContractAssembly> assemblyLoadResult = this.assemblyLoader.Load(byteCode);

            if (!assemblyLoadResult.IsSuccess)
            {
                this.logger.LogTrace(assemblyLoadResult.Error);

                return(Result.Fail <IContract>(assemblyLoadResult.Error));
            }

            IContractAssembly contractAssembly = assemblyLoadResult.Value;

            Type type = contractAssembly.GetType(typeName);

            if (type == null)
            {
                const string typeNotFoundError = "Type not found!";

                this.logger.LogTrace(typeNotFoundError);

                return(Result.Fail <IContract>(typeNotFoundError));
            }

            IContract contract;

            try
            {
                contract = Contract.CreateUninitialized(type, contractState, address);
            }
            catch (Exception e)
            {
                this.logger.LogError("Exception occurred: {0}", e.ToString());

                return(Result.Fail <IContract>("Exception occurred while instantiating contract instance"));
            }

            return(Result.Ok(contract));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates a new instance of a smart contract by invoking the contract's constructor
        /// </summary>
        public VmExecutionResult Create(IStateRepository repository,
                                        ISmartContractState contractState,
                                        ExecutionContext executionContext,
                                        byte[] contractCode,
                                        object[] parameters,
                                        string typeName = null)
        {
            // The type and code that will ultimately be executed. Assigned based on which method we use to rewrite contract code.
            string    typeToInstantiate;
            IContract contract;
            Observer  previousObserver = null;

            // Hash the code
            byte[]  codeHash        = HashHelper.Keccak256(contractCode);
            uint256 codeHashUint256 = new uint256(codeHash);

            // Lets see if we already have an assembly
            CachedAssemblyPackage assemblyPackage = this.assemblyCache.Retrieve(codeHashUint256);

            if (assemblyPackage != null)
            {
                // If the assembly is in the cache, keep a reference to its observer around.
                // We might be in a nested execution for the same assembly,
                // in which case we need to restore the previous observer later.
                previousObserver = assemblyPackage.Assembly.GetObserver();

                typeToInstantiate = typeName ?? assemblyPackage.Assembly.DeployedType.Name;

                Type type = assemblyPackage.Assembly.GetType(typeToInstantiate);

                uint160 address = contractState.Message.ContractAddress.ToUint160();
                contract = Contract.CreateUninitialized(type, contractState, address);


                // TODO: Type not found?

                // TODO: Setting observer error?

                // TODO: Error instantiating contract?
            }
            else
            {
                // Create from scratch
                // Validate then rewrite the entirety of the incoming code.
                Result <IContractModuleDefinition> moduleResult = this.moduleDefinitionReader.Read(contractCode);

                if (moduleResult.IsFailure)
                {
                    this.logger.LogDebug(moduleResult.Error);
                    this.logger.LogTrace("(-)[CONTRACT_BYTECODE_INVALID]");
                    return(VmExecutionResult.Fail(VmExecutionErrorKind.LoadFailed,
                                                  "Contract bytecode is not valid IL."));
                }

                using (IContractModuleDefinition moduleDefinition = moduleResult.Value)
                {
                    SmartContractValidationResult validation = moduleDefinition.Validate(this.validator);

                    // If validation failed, refund the sender any remaining gas.
                    if (!validation.IsValid)
                    {
                        this.logger.LogTrace("(-)[CONTRACT_VALIDATION_FAILED]");
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.ValidationFailed,
                                                      new SmartContractValidationException(validation.Errors).ToString()));
                    }

                    var rewriter = new ObserverInstanceRewriter();

                    if (!this.Rewrite(moduleDefinition, rewriter))
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.RewriteFailed, "Rewrite module failed"));
                    }

                    Result <ContractByteCode> getCodeResult = this.GetByteCode(moduleDefinition);

                    if (!getCodeResult.IsSuccess)
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.RewriteFailed, "Serialize module failed"));
                    }

                    // Everything worked. Assign what will get executed.
                    typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name;
                    ContractByteCode code = getCodeResult.Value;

                    Result <IContract> contractLoadResult = this.Load(
                        code,
                        typeToInstantiate,
                        contractState.Message.ContractAddress.ToUint160(),
                        contractState);

                    if (!contractLoadResult.IsSuccess)
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.LoadFailed, contractLoadResult.Error));
                    }

                    contract = contractLoadResult.Value;

                    assemblyPackage = new CachedAssemblyPackage(new ContractAssembly(contract.Type.Assembly));

                    // Cache this completely validated and rewritten contract to reuse later.
                    this.assemblyCache.Store(codeHashUint256, assemblyPackage);
                }
            }

            this.LogExecutionContext(contract.State.Block, contract.State.Message, contract.Address);

            // Set the code and the Type before the method is invoked
            repository.SetCode(contract.Address, contractCode);
            repository.SetContractType(contract.Address, typeToInstantiate);

            // Set Observer and load and execute.
            assemblyPackage.Assembly.SetObserver(executionContext.Observer);

            // Invoke the constructor of the provided contract code
            IContractInvocationResult invocationResult = contract.InvokeConstructor(parameters);

            // Always reset the observer, even if the previous was null.
            assemblyPackage.Assembly.SetObserver(previousObserver);

            if (!invocationResult.IsSuccess)
            {
                this.logger.LogDebug("CREATE_CONTRACT_INSTANTIATION_FAILED");
                return(GetInvocationVmErrorResult(invocationResult));
            }

            this.logger.LogDebug("CREATE_CONTRACT_INSTANTIATION_SUCCEEDED");

            return(VmExecutionResult.Ok(invocationResult.Return, typeToInstantiate));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Invokes a method on an existing smart contract
        /// </summary>
        public VmExecutionResult ExecuteMethod(ISmartContractState contractState, ExecutionContext executionContext,
                                               MethodCall methodCall, byte[] contractCode, string typeName)
        {
            IContract contract;
            Observer  previousObserver = null;

            // Hash the code
            byte[]  codeHash        = HashHelper.Keccak256(contractCode);
            uint256 codeHashUint256 = new uint256(codeHash);

            // Lets see if we already have an assembly
            CachedAssemblyPackage assemblyPackage = this.assemblyCache.Retrieve(codeHashUint256);

            if (assemblyPackage != null)
            {
                // If the assembly is in the cache, keep a reference to its observer around.
                // We might be in a nested execution for the same assembly,
                // in which case we need to restore the previous observer later.
                previousObserver = assemblyPackage.Assembly.GetObserver();

                Type type = assemblyPackage.Assembly.GetType(typeName);

                uint160 address = contractState.Message.ContractAddress.ToUint160();
                contract = Contract.CreateUninitialized(type, contractState, address);
            }
            else
            {
                // Rewrite from scratch.
                using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractCode).Value)
                {
                    var rewriter = new ObserverInstanceRewriter();

                    if (!this.Rewrite(moduleDefinition, rewriter))
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.RewriteFailed, "Rewrite module failed"));
                    }

                    Result <ContractByteCode> getCodeResult = this.GetByteCode(moduleDefinition);

                    if (!getCodeResult.IsSuccess)
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.RewriteFailed, "Serialize module failed"));
                    }

                    // Everything worked. Assign the code that will be executed.
                    ContractByteCode code = getCodeResult.Value;

                    // Creating a new observer instance here is necessary due to nesting.
                    // If a nested call takes place it will use a new gas meter instance,
                    // due to the fact that the nested call's gas limit may be specified by the user.
                    // Because of that we can't reuse the same observer for a single execution.

                    Result <IContract> contractLoadResult = this.Load(
                        code,
                        typeName,
                        contractState.Message.ContractAddress.ToUint160(),
                        contractState);

                    if (!contractLoadResult.IsSuccess)
                    {
                        return(VmExecutionResult.Fail(VmExecutionErrorKind.LoadFailed, contractLoadResult.Error));
                    }

                    contract = contractLoadResult.Value;

                    assemblyPackage = new CachedAssemblyPackage(new ContractAssembly(contract.Type.Assembly));

                    // Cache this completely validated and rewritten contract to reuse later.
                    this.assemblyCache.Store(codeHashUint256, assemblyPackage);
                }
            }

            this.LogExecutionContext(contract.State.Block, contract.State.Message, contract.Address);

            // Set new Observer and load and execute.
            assemblyPackage.Assembly.SetObserver(executionContext.Observer);

            IContractInvocationResult invocationResult = contract.Invoke(methodCall);

            // Always reset the observer, even if the previous was null.
            assemblyPackage.Assembly.SetObserver(previousObserver);

            if (!invocationResult.IsSuccess)
            {
                this.logger.LogTrace("(-)[CALLCONTRACT_INSTANTIATION_FAILED]");

                return(GetInvocationVmErrorResult(invocationResult));
            }

            this.logger.LogDebug("CALL_CONTRACT_INSTANTIATION_SUCCEEDED");

            return(VmExecutionResult.Ok(invocationResult.Return, typeName));
        }