/// <summary> /// Invokes a method on an existing smart contract /// </summary> public VmExecutionResult ExecuteMethod(ISmartContractState contractState, MethodCall methodCall, byte[] contractCode, string typeName) { this.logger.LogTrace("(){0}:{1}", nameof(methodCall.Name), methodCall.Name); ContractByteCode code; // Code we're loading from database - can assume it's valid. using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractCode).Value) { var observer = new Observer(contractState.GasMeter, MemoryUnitLimit); var rewriter = new ObserverRewriter(observer); moduleDefinition.Rewrite(rewriter); code = moduleDefinition.ToByteCode(); } Result <IContract> contractLoadResult = this.Load( code, typeName, contractState.Message.ContractAddress.ToUint160(this.network), contractState); if (!contractLoadResult.IsSuccess) { LogErrorMessage(contractLoadResult.Error); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]"); return(VmExecutionResult.Fail(VmExecutionErrorKind.LoadFailed, contractLoadResult.Error)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address); IContractInvocationResult invocationResult = contract.Invoke(methodCall); if (!invocationResult.IsSuccess) { this.logger.LogTrace("(-)[CALLCONTRACT_INSTANTIATION_FAILED]"); return(GetInvocationVmErrorResult(invocationResult)); } this.logger.LogTrace("[CALL_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-)"); return(VmExecutionResult.Ok(invocationResult.Return, typeName)); }
/// <summary> /// Invokes a method on an existing smart contract /// </summary> public VmExecutionResult ExecuteMethod(ISmartContractState contractState, MethodCall methodCall, byte[] contractCode, string typeName) { this.logger.LogTrace("(){0}:{1}", nameof(methodCall.Name), methodCall.Name); ContractByteCode code; using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractCode)) { moduleDefinition.InjectMethodGas(typeName, methodCall); code = moduleDefinition.ToByteCode(); } Result <IContract> contractLoadResult = this.Load( code, typeName, contractState.Message.ContractAddress.ToUint160(this.network), contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]"); return(VmExecutionResult.Error(exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address); IContractInvocationResult invocationResult = contract.Invoke(methodCall); if (!invocationResult.IsSuccess) { this.logger.LogTrace("(-)[CALLCONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(new Exception("Method invocation failed!"))); } this.logger.LogTrace("[CALL_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-)"); return(VmExecutionResult.Success(invocationResult.Return, typeName)); }
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")); } }
public void VM_ExecuteContract_CachedAssembly_WithExistingObserver() { ContractCompilationResult compilationResult = ContractCompiler.Compile( @" using System; using Stratis.SmartContracts; public class Contract : SmartContract { public Contract(ISmartContractState state) : base(state) {} public void Test() {} } "); Assert.True(compilationResult.Success); byte[] contractExecutionCode = compilationResult.Compilation; byte[] codeHash = HashHelper.Keccak256(contractExecutionCode); byte[] rewrittenCode; // Rewrite the assembly to have an observer. using (IContractModuleDefinition moduleDefinition = this.context.ModuleDefinitionReader.Read(contractExecutionCode).Value) { var rewriter = new ObserverInstanceRewriter(); moduleDefinition.Rewrite(rewriter); rewrittenCode = moduleDefinition.ToByteCode().Value; } var contractAssembly = new ContractAssembly(Assembly.Load(rewrittenCode)); // Cache the assembly. this.context.ContractCache.Store(new uint256(codeHash), new CachedAssemblyPackage(contractAssembly)); // Set an observer on the cached rewritten assembly. var initialObserver = new Observer(new GasMeter((Gas)(this.gasMeter.GasAvailable + 1000)), new MemoryMeter(100_000)); Assert.True(contractAssembly.SetObserver(initialObserver)); var callData = new MethodCall("Test"); // Run the execution with an empty gas meter, which means it should fail if the correct observer is used. var emptyGasMeter = new GasMeter((Gas)0); var executionContext = new ExecutionContext(new Observer(emptyGasMeter, new MemoryMeter(100_000))); VmExecutionResult result = this.vm.ExecuteMethod(this.contractState, executionContext, callData, contractExecutionCode, "Contract"); CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash)); // Check that it's still cached. Assert.NotNull(cachedAssembly); // Check that the observer has been reset to the original. Assert.Same(initialObserver, cachedAssembly.Assembly.GetObserver()); Assert.False(result.IsSuccess); Assert.Equal(VmExecutionErrorKind.OutOfGas, result.Error.ErrorKind); }
private IContract GetContractAfterRewrite(string filename) { ContractCompilationResult compilationResult = ContractCompiler.CompileFile(filename); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); return(Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null)); }
public void TestGasInjector_NestedType_GasInjectionSucceeds() { ContractCompilationResult compilationResult = ContractCompiler.Compile(@" using System; using Stratis.SmartContracts; public class Test : SmartContract { public Test(ISmartContractState state): base(state) { var other = new Other.NestedOther(); other.Loop(); } } public static class Other { public struct NestedOther { public void Loop() { while(true) {}} } } "); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.InvokeConstructor(null); Assert.False(result.IsSuccess); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); }
public void TestGasInjector_ContractMethodWithRecursion_GasInjectionSucceeds() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Recursion.cs"); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var callData = new MethodCall(nameof(Recursion.DoRecursion)); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); Assert.True(result.IsSuccess); Assert.True(this.gasMeter.GasConsumed > 0); }
public void SmartContracts_GasInjector_MultipleParamConstructorGasInjectedSuccess() { ContractCompilationResult compilationResult = ContractCompiler.Compile(TestMultipleConstructorSource); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.InvokeConstructor(new[] { "Test Owner" }); // Number here shouldn't be hardcoded - note this is really only to let us know of consensus failure Assert.Equal((RuntimeObserver.Gas) 328, this.gasMeter.GasConsumed); }
public void TestGasInjector_OutOfGasFails() { ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/OutOfGasTest.cs"); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var callData = new MethodCall("UseAllGas"); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); // Because our contract contains an infinite loop, we want to kill our test after // some amount of time without achieving a result. 3 seconds is an arbitrarily high enough timeout // for the method body to have finished execution while minimising the amount of time we spend // running tests // If you're running with the debugger on this will obviously be a source of failures IContractInvocationResult result = TimeoutHelper.RunCodeWithTimeout(5, () => contract.Invoke(callData)); Assert.False(result.IsSuccess); Assert.Equal((RuntimeObserver.Gas) 0, this.gasMeter.GasAvailable); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); }
/// <summary> /// Creates a new instance of a smart contract by invoking the contract's constructor /// </summary> public VmExecutionResult Create(IGasMeter gasMeter, IContractState repository, ICreateData createData, ITransactionContext transactionContext, string typeName = null) { this.logger.LogTrace("()"); // TODO: Spend Validation + Creation Fee here. string typeToInstantiate; ContractByteCode code; // Decompile the contract execution code and validate it. using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(createData.ContractExecutionCode)) { 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.Error(gasMeter.GasConsumed, new SmartContractValidationException(validation.Errors))); } typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name; moduleDefinition.InjectConstructorGas(); code = moduleDefinition.ToByteCode(); } var internalTransferList = new List <TransferInfo>(); uint160 address = this.addressGenerator.GenerateAddress(transactionContext.TransactionHash, transactionContext.GetNonceAndIncrement()); var contractLogger = new ContractLogHolder(this.network); ISmartContractState contractState = this.SetupState(contractLogger, internalTransferList, gasMeter, repository, transactionContext, address); Result <IContract> contractLoadResult = this.Load( code, typeToInstantiate, address, contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address, createData); // Create an account for the contract in the state repository. repository.CreateAccount(contract.Address); // Invoke the constructor of the provided contract code IContractInvocationResult invocationResult = contract.InvokeConstructor(createData.MethodParameters); if (!invocationResult.IsSuccess) { this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(gasMeter.GasConsumed, new Exception("Constructor invocation failed!"))); } this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}, {2}={3}", nameof(contract.Address), contract.Address, nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); repository.SetCode(contract.Address, createData.ContractExecutionCode); repository.SetContractType(contract.Address, contract.Type.Name); return(VmExecutionResult.CreationSuccess(contract.Address, internalTransferList, gasMeter.GasConsumed, invocationResult.Return, contractLogger.GetRawLogs())); }
/// <summary> /// Invokes a method on an existing smart contract /// </summary> public VmExecutionResult ExecuteMethod( IGasMeter gasMeter, IContractState repository, ICallData callData, ITransactionContext transactionContext) { this.logger.LogTrace("(){0}:{1}", nameof(callData.MethodName), callData.MethodName); if (callData.MethodName == null) { this.logger.LogTrace("(-)[CALLCONTRACT_METHODNAME_NOT_GIVEN]"); return(VmExecutionResult.Error(gasMeter.GasConsumed, null)); } byte[] contractExecutionCode = repository.GetCode(callData.ContractAddress); string typeName = repository.GetContractType(callData.ContractAddress); if (contractExecutionCode == null) { return(VmExecutionResult.Error(gasMeter.GasConsumed, new SmartContractDoesNotExistException(callData.MethodName))); } // TODO consolidate this with CallData. MethodCall methodCall = new MethodCall(callData.MethodName, callData.MethodParameters); ContractByteCode code; using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractExecutionCode)) { moduleDefinition.InjectMethodGas(typeName, methodCall); code = moduleDefinition.ToByteCode(); } var internalTransferList = new List <TransferInfo>(); var contractLogger = new ContractLogHolder(this.network); ISmartContractState contractState = this.SetupState(contractLogger, internalTransferList, gasMeter, repository, transactionContext, callData.ContractAddress); Result <IContract> contractLoadResult = this.Load( code, typeName, callData.ContractAddress, contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, contract.State.Block, contract.State.Message, contract.Address, callData); IContractInvocationResult invocationResult = contract.Invoke(methodCall); if (!invocationResult.IsSuccess) { this.logger.LogTrace("(-)[CALLCONTRACT_INSTANTIATION_FAILED]:{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Error(gasMeter.GasConsumed, new Exception("Method invocation failed!"))); } this.logger.LogTrace("[CALL_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}", nameof(gasMeter.GasConsumed), gasMeter.GasConsumed); return(VmExecutionResult.Success(internalTransferList, gasMeter.GasConsumed, invocationResult.Return, contractLogger.GetRawLogs())); }
/// <summary> /// Creates a new instance of a smart contract by invoking the contract's constructor /// </summary> public VmExecutionResult Create(IContractState repository, ISmartContractState contractState, byte[] contractCode, object[] parameters, string typeName = null) { this.logger.LogTrace("()"); string typeToInstantiate; ContractByteCode code; // Decompile the contract execution code and validate it. using (IContractModuleDefinition moduleDefinition = this.moduleDefinitionReader.Read(contractCode)) { 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.Error(new SmartContractValidationException(validation.Errors))); } typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name; moduleDefinition.InjectConstructorGas(); code = moduleDefinition.ToByteCode(); } Result <IContract> contractLoadResult = this.Load( code, typeToInstantiate, contractState.Message.ContractAddress.ToUint160(this.network), contractState); if (!contractLoadResult.IsSuccess) { // TODO this is temporary until we improve error handling overloads var exception = new Exception(contractLoadResult.Error); LogException(exception); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]"); return(VmExecutionResult.Error(exception)); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, 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); // Invoke the constructor of the provided contract code IContractInvocationResult invocationResult = contract.InvokeConstructor(parameters); if (!invocationResult.IsSuccess) { this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(new Exception("Constructor invocation failed!"))); } this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}", nameof(contract.Address), contract.Address); return(VmExecutionResult.Success(invocationResult.Return, typeToInstantiate)); }
public void SmartContracts_GasInjector_MultipleParamConstructorGasInjectedSuccess() { SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(TestMultipleConstructorSource); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes); module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.InvokeConstructor(new[] { "Test Owner" }); // Constructor: 15 // Property setter: 12 // Storage: 150 Assert.Equal((Gas)177, this.gasMeter.GasConsumed); }
public void TestGasInjector_OutOfGasFails() { SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/OutOfGasTest.cs"); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var callData = new MethodCall("UseAllGas"); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes); module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); Assert.False(result.IsSuccess); Assert.Equal((Gas)0, this.gasMeter.GasAvailable); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); Assert.Equal(this.gasMeter.GasLimit, this.gasMeter.GasConsumed); }
public void TestGasInjector() { SmartContractCompilationResult compilationResult = SmartContractCompiler.Compile(TestSource); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(AppContext.BaseDirectory); int aimGasAmount; using (ModuleDefinition moduleDefinition = ModuleDefinition.ReadModule( new MemoryStream(originalAssemblyBytes), new ReaderParameters { AssemblyResolver = resolver })) { TypeDefinition contractType = moduleDefinition.GetType(ContractName); MethodDefinition testMethod = contractType.Methods.FirstOrDefault(x => x.Name == MethodName); aimGasAmount = testMethod?.Body?.Instructions? .Count ?? 10000000; } var callData = new MethodCall("TestMethod", new object[] { 1 }); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes); module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); Assert.Equal((ulong)aimGasAmount, this.state.GasMeter.GasConsumed); }
public void TestGasInjector() { ContractCompilationResult compilationResult = ContractCompiler.Compile(TestSource); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(AppContext.BaseDirectory); using (ModuleDefinition moduleDefinition = ModuleDefinition.ReadModule( new MemoryStream(originalAssemblyBytes), new ReaderParameters { AssemblyResolver = resolver })) { TypeDefinition contractType = moduleDefinition.GetType(ContractName); MethodDefinition testMethod = contractType.Methods.FirstOrDefault(x => x.Name == MethodName); } var callData = new MethodCall("TestMethod", new object[] { 1 }); IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assembly = this.assemblyLoader.Load(module.ToByteCode()); IContract contract = Contract.CreateUninitialized(assembly.Value.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); // Number here shouldn't be hardcoded - note this is really only to let us know of consensus failure Assert.Equal(22uL, this.gasMeter.GasConsumed); }
/// <summary> /// Creates a new instance of a smart contract by invoking the contract's constructor /// </summary> public VmExecutionResult Create(IStateRepository repository, ISmartContractState contractState, byte[] contractCode, object[] parameters, string typeName = null) { this.logger.LogTrace("()"); string typeToInstantiate; ContractByteCode code; // Decompile the contract execution code Result <IContractModuleDefinition> moduleResult = this.moduleDefinitionReader.Read(contractCode); if (moduleResult.IsFailure) { this.logger.LogTrace("(-)[CONTRACT_BYTECODE_INVALID]"); return(VmExecutionResult.Error(new ContractErrorMessage("Contract bytecode is not valid IL."))); } // Validate contract execution code 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]"); // TODO: List errors by string. return(VmExecutionResult.Error(new ContractErrorMessage(new SmartContractValidationException(validation.Errors).ToString()))); } typeToInstantiate = typeName ?? moduleDefinition.ContractType.Name; var observer = new Observer(contractState.GasMeter, MemoryUnitLimit); var rewriter = new ObserverRewriter(observer); moduleDefinition.Rewrite(rewriter); code = moduleDefinition.ToByteCode(); } Result <IContract> contractLoadResult = this.Load( code, typeToInstantiate, contractState.Message.ContractAddress.ToUint160(this.network), contractState); if (!contractLoadResult.IsSuccess) { LogErrorMessage(contractLoadResult.Error); this.logger.LogTrace("(-)[LOAD_CONTRACT_FAILED]"); return(VmExecutionResult.Error(new ContractErrorMessage(contractLoadResult.Error))); } IContract contract = contractLoadResult.Value; LogExecutionContext(this.logger, 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); // Invoke the constructor of the provided contract code IContractInvocationResult invocationResult = contract.InvokeConstructor(parameters); if (!invocationResult.IsSuccess) { this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_FAILED]"); return(VmExecutionResult.Error(invocationResult.ErrorMessage)); } this.logger.LogTrace("[CREATE_CONTRACT_INSTANTIATION_SUCCEEDED]"); this.logger.LogTrace("(-):{0}={1}", nameof(contract.Address), contract.Address); return(VmExecutionResult.Success(invocationResult.Return, typeToInstantiate)); }
public void Separate_Threads_Have_Different_Observer_Instances() { // Create a contract assembly. ContractCompilationResult compilationResult = ContractCompiler.Compile(TestSource); Assert.True(compilationResult.Success); byte[] originalAssemblyBytes = compilationResult.Compilation; IContractModuleDefinition module = this.moduleReader.Read(originalAssemblyBytes).Value; module.Rewrite(this.rewriter); CSharpFunctionalExtensions.Result <IContractAssembly> assemblyLoadResult = this.assemblyLoader.Load(module.ToByteCode()); IContractAssembly assembly = assemblyLoadResult.Value; var threadCount = 10; var observers = new Observer[threadCount]; var countdown = new CountdownEvent(threadCount); var threads = new Thread[threadCount]; for (var i = 0; i < threadCount; i++) { // Create a fake observer with a counter. var observer = new Observer(new GasMeter((Gas)1000000), new MemoryMeter(1000000)); observers[i] = observer; // Set a different observer on each thread. // Invoke the same method on each thread. Thread newThread = new Thread(() => { assembly.SetObserver(observer); Assert.Same(observer, assembly.GetObserver()); var callData = new MethodCall("TestMethod", new object[] { 1 }); IContract contract = Contract.CreateUninitialized(assembly.GetType(module.ContractType.Name), this.state, null); IContractInvocationResult result = contract.Invoke(callData); countdown.Signal(); }); newThread.Name = i.ToString(); threads[i] = newThread; } // Start the threads on a separate loop to ensure all time is spent on processing. foreach (Thread thread in threads) { thread.Start(); } countdown.Wait(); foreach (Observer observer in observers) { Assert.Equal(observers[0].GasMeter.GasConsumed, observer.GasMeter.GasConsumed); Assert.Equal(observers[0].MemoryMeter.MemoryConsumed, observer.MemoryMeter.MemoryConsumed); } }