public void Contract_Transfer_To_Other_Contract_Success()
        {
            // There is code at the destination address, which causes an internal call to the receive method
            var vmExecutionResult = VmExecutionResult.Success(true, "Test");
            var code     = new byte[1];
            var typeName = "Test";

            var contractTransferMessage = new ContractTransferMessage(
                uint160.One,
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000)
                );

            // Code must be returned for this test to ensure we apply the call.
            this.contractStateRoot
            .Setup(sr => sr.GetCode(contractTransferMessage.To))
            .Returns(code);

            this.contractStateRoot
            .Setup(sr => sr.GetContractType(contractTransferMessage.To))
            .Returns(typeName);

            this.vm.Setup(v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), contractTransferMessage.Method, code, typeName))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            // Return the sent amount + 1
            state.Setup(s => s.GetBalance(contractTransferMessage.From)).Returns(contractTransferMessage.Amount + 1);

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, contractTransferMessage);

            // Verify we check the balance of the sender first
            state.Verify(s => s.GetBalance(contractTransferMessage.From));

            // Verify we get the code from the destination address' code cache
            this.contractStateRoot.Verify(s => s.GetCode(contractTransferMessage.To), Times.Once);

            // Verify we set up the smart contract state
            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <GasMeter>(), contractTransferMessage.To, contractTransferMessage, this.contractStateRoot.Object));

            // Verify the VM was invoked
            this.vm.Verify(v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), contractTransferMessage.Method, code, typeName), Times.Once);

            // Verify the value was added to the internal transfer list
            state.Verify(s => s.AddInternalTransfer(It.Is <TransferInfo>(t => t.From == contractTransferMessage.From &&
                                                                         t.To == contractTransferMessage.To &&
                                                                         t.Value == contractTransferMessage.Amount)));

            Assert.True(result.IsSuccess);
            Assert.NotNull(result.Success);
            Assert.Equal(contractTransferMessage.To, result.Success.ContractAddress);
            Assert.Equal(vmExecutionResult.Result, result.Success.ExecutionResult);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
Ejemplo n.º 2
0
        public void InternalCreate_Vm_Error()
        {
            var newContractAddress = uint160.One;

            var vmExecutionResult = VmExecutionResult.Fail(VmExecutionErrorKind.InvocationFailed, "Error");

            // Code must have a length to pass precondition checks.
            var code     = new byte[1];
            var typeName = "Test";

            var internalCreateMessage = new InternalCreateMessage(
                uint160.Zero,
                10,
                (RuntimeObserver.Gas)(GasPriceList.BaseCost + 100000),
                new object[] { },
                typeName
                );

            this.vm.Setup(v =>
                          v.Create(It.IsAny <IStateRepository>(),
                                   It.IsAny <ISmartContractState>(),
                                   It.IsAny <ExecutionContext>(),
                                   It.IsAny <byte[]>(),
                                   It.IsAny <object[]>(),
                                   It.IsAny <string>()))
            .Returns(vmExecutionResult);

            // Need to return code for the sender
            this.contractStateRoot
            .Setup(sr => sr.GetCode(internalCreateMessage.From))
            .Returns(code);

            var state = new Mock <IState>();

            state.Setup(s => s.GetBalance(internalCreateMessage.From)).Returns(internalCreateMessage.Amount + 1);
            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);
            state.Setup(s => s.GenerateAddress(It.IsAny <IAddressGenerator>())).Returns(newContractAddress);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, internalCreateMessage);

            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <RuntimeObserver.IGasMeter>(), newContractAddress, internalCreateMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.Create(
                    this.contractStateRoot.Object,
                    It.IsAny <ISmartContractState>(),
                    It.IsAny <ExecutionContext>(),
                    code,
                    internalCreateMessage.Parameters,
                    internalCreateMessage.Type),
                Times.Once);

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Equal(result.Error.VmError, vmExecutionResult.Error.Message);
            Assert.Equal(StateTransitionErrorKind.VmError, result.Error.Kind);
            Assert.Equal(GasPriceList.CreateCost, result.GasConsumed);
        }
Ejemplo n.º 3
0
        public void SmartContracts_GasInjector_MultipleParamConstructorGasInjectedSuccess()
        {
            SmartContractCompilationResult compilationResult =
                SmartContractCompiler.Compile(TestMultipleConstructorSource);

            Assert.True(compilationResult.Success);
            byte[] originalAssemblyBytes = compilationResult.Compilation;

            var gasLimit = (Gas)500000;
            var gasMeter = new GasMeter(gasLimit);

            var callData = new CreateData(gasLimit, originalAssemblyBytes, new[] { "Test Owner" });

            var transactionContext = new TransactionContext(
                txHash: uint256.One,
                blockHeight: 0,
                coinbase: TestAddress.ToUint160(this.network),
                sender: TestAddress.ToUint160(this.network),
                amount: 0
                );

            VmExecutionResult result = this.vm.Create(gasMeter,
                                                      this.repository,
                                                      callData, transactionContext);

            // Constructor: 15
            // Property setter: 12
            // Storage: 150
            Assert.Equal((Gas)177, result.GasConsumed);
        }
Ejemplo n.º 4
0
        public void VM_ExecuteContract_WithParameters()
        {
            ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/StorageTest.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            byte[] codeHash = HashHelper.Keccak256(contractExecutionCode);

            var methodParameters = new object[] { (int)5 };
            var callData         = new MethodCall("OneParamTest", methodParameters);

            var executionContext = new ExecutionContext(new Observer(this.gasMeter, new MemoryMeter(100_000)));

            VmExecutionResult result = this.vm.ExecuteMethod(this.contractState,
                                                             executionContext,
                                                             callData,
                                                             contractExecutionCode, "StorageTest");

            CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash));

            // Check that it's been cached.
            Assert.NotNull(cachedAssembly);

            // Check that the observer has been reset.
            Assert.Null(cachedAssembly.Assembly.GetObserver());
            Assert.True(result.IsSuccess);
            Assert.Null(result.Error);
            Assert.Equal(methodParameters[0], result.Success.Result);
        }
Ejemplo n.º 5
0
        public void TestGasInjector_OutOfGasFails()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/OutOfGasTest.cs");

            Assert.True(compilationResult.Success);

            byte[] originalAssemblyBytes = compilationResult.Compilation;

            var gasLimit = (Gas)500000;
            var gasMeter = new GasMeter(gasLimit);

            uint160 address = TestAddress.ToUint160(this.network);

            var callData = new CallData(gasLimit, address, "UseAllGas");

            var transactionContext = new TransactionContext(uint256.One, 0, address, address, 0);

            this.repository.SetCode(callData.ContractAddress, originalAssemblyBytes);
            this.repository.SetContractType(callData.ContractAddress, "OutOfGasTest");

            VmExecutionResult result = this.vm.ExecuteMethod(gasMeter, this.repository, callData, transactionContext);

            Assert.NotNull(result.ExecutionException);
            Assert.Equal((Gas)0, gasMeter.GasAvailable);
            Assert.Equal(gasLimit, result.GasConsumed);
            Assert.Equal(gasLimit, gasMeter.GasConsumed);
        }
        public void VM_Throws_Exception_CanCatch()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ThrowExceptionContract.cs");

            Assert.True(compilationResult.Success);

            byte[] contractCode = compilationResult.Compilation;

            var gasLimit = (Gas)10000;
            var gasMeter = new GasMeter(gasLimit);

            uint160 address = TestAddress.ToUint160(this.network);

            var callData = new CallData(gasLimit, address, "ThrowException");

            this.repository.SetCode(address, contractCode);
            this.repository.SetContractType(address, "ThrowExceptionContract");
            var transactionContext = new TransactionContext(uint256.One, 0, address, address, 0);

            VmExecutionResult result = this.vm.ExecuteMethod(gasMeter,
                                                             this.repository,
                                                             callData,
                                                             transactionContext);

            Assert.Equal(typeof(Exception), result.ExecutionException.GetType());
        }
        public void VM_Throws_Exception_CanCatch()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/ThrowExceptionContract.cs");

            Assert.True(compilationResult.Success);

            byte[] contractCode = compilationResult.Compilation;

            var gasLimit = (Gas)10000;
            var gasMeter = new GasMeter(gasLimit);

            var internalTxExecutorFactory = new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);
            var vm = new ReflectionVirtualMachine(this.validator, internalTxExecutorFactory, this.loggerFactory, this.network, this.addressGenerator);

            uint160 address = TestAddress.ToUint160(this.network);

            var callData = new CallData(gasLimit, address, "ThrowException");

            this.repository.SetCode(address, contractCode);
            this.repository.SetContractType(address, "ThrowExceptionContract");
            var transactionContext = new TransactionContext(uint256.One, 0, address, address, 0);

            VmExecutionResult result = vm.ExecuteMethod(gasMeter,
                                                        this.repository,
                                                        callData,
                                                        transactionContext);

            Assert.Equal(typeof(Exception), result.ExecutionException.GetType());
        }
        public void VM_ExecuteContract_ClearStorage()
        {
            ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ClearStorage.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            var    callData = new MethodCall(nameof(ClearStorage.ClearKey), new object[] { });

            uint160 contractAddress = this.contractState.Message.ContractAddress.ToUint160();

            byte[] keyToClear = Encoding.UTF8.GetBytes(ClearStorage.KeyToClear);

            // Set a value to be cleared
            this.state.SetStorageValue(contractAddress, keyToClear, new byte[] { 1, 2, 3 });

            VmExecutionResult result = this.vm.ExecuteMethod(this.contractState,
                                                             this.gasMeter,
                                                             callData,
                                                             contractExecutionCode,
                                                             nameof(ClearStorage));

            Assert.Null(result.Error);
            Assert.Null(this.state.GetStorageValue(contractAddress, keyToClear));
        }
Ejemplo n.º 9
0
        public void TestGasInjector_ContractMethodWithRecursion_GasInjectionSucceeds()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Recursion.cs");

            Assert.True(compilationResult.Success);

            byte[] originalAssemblyBytes = compilationResult.Compilation;

            var gasLimit = (Gas)500000;
            var gasMeter = new GasMeter(gasLimit);

            uint160 address = TestAddress.ToUint160(this.network);

            var callData = new CallData(gasLimit, address, nameof(Recursion.DoRecursion));

            var transactionContext = new TransactionContext(uint256.One, 0, address, address, 0);

            this.repository.SetCode(callData.ContractAddress, originalAssemblyBytes);
            this.repository.SetContractType(callData.ContractAddress, nameof(Recursion));

            VmExecutionResult result = this.vm.ExecuteMethod(gasMeter, this.repository, callData, transactionContext);

            Assert.Null(result.ExecutionException);
            Assert.True(result.GasConsumed > 0);
        }
        public void InternalCall_Vm_Error()
        {
            var vmExecutionResult = VmExecutionResult.Fail(VmExecutionErrorKind.InvocationFailed, "Error");

            // Code must have a length to pass precondition checks.
            var code     = new byte[1];
            var typeName = "Test";

            var internalCallMessage = new InternalCallMessage(
                uint160.One,
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000),
                new MethodCall("Test", new object[] { })
                );

            this.vm.Setup(v => v.ExecuteMethod(
                              It.IsAny <ISmartContractState>(),
                              It.IsAny <IGasMeter>(),
                              internalCallMessage.Method,
                              code,
                              typeName))
            .Returns(vmExecutionResult);

            this.contractStateRoot
            .Setup(sr => sr.GetCode(internalCallMessage.To))
            .Returns(code);

            this.contractStateRoot
            .Setup(sr => sr.GetContractType(internalCallMessage.To))
            .Returns(typeName);

            var state = new Mock <IState>();

            state.Setup(s => s.GetBalance(internalCallMessage.From))
            .Returns(internalCallMessage.Amount + 1);
            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, internalCallMessage);

            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <IGasMeter>(), internalCallMessage.To, internalCallMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.ExecuteMethod(
                    It.IsAny <ISmartContractState>(),
                    It.IsAny <IGasMeter>(),
                    internalCallMessage.Method,
                    code,
                    typeName),
                Times.Once);

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Equal(result.Error.VmError, vmExecutionResult.Error.Message);
            Assert.Equal(StateTransitionErrorKind.VmError, result.Error.Kind);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
        public void ExternalCall_Success()
        {
            var gasLimit          = (Gas)(GasPriceList.BaseCost + 100000);
            var vmExecutionResult = VmExecutionResult.Ok(true, "Test");

            // Code must have a length to pass precondition checks.
            var code     = new byte[1];
            var typeName = "Test";

            var externalCallMessage = new ExternalCallMessage(
                uint160.Zero,
                uint160.Zero,
                0,
                gasLimit,
                new MethodCall("Test", null)
                );

            this.contractStateRoot
            .Setup(sr => sr.GetCode(externalCallMessage.To))
            .Returns(code);

            this.contractStateRoot
            .Setup(sr => sr.GetContractType(externalCallMessage.To))
            .Returns(typeName);

            this.vm.Setup(v =>
                          v.ExecuteMethod(It.IsAny <ISmartContractState>(), externalCallMessage.Method, code, typeName))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, externalCallMessage);

            state.Verify(s => s.AddInitialTransfer(It.Is <TransferInfo>(t => t.Value == externalCallMessage.Amount && t.To == externalCallMessage.To)));

            this.contractStateRoot.Verify(sr => sr.GetCode(externalCallMessage.To), Times.Once);

            this.contractStateRoot.Verify(sr => sr.GetContractType(externalCallMessage.To), Times.Once);

            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <GasMeter>(), externalCallMessage.To, externalCallMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), externalCallMessage.Method, code, typeName),
                Times.Once);

            Assert.True(result.IsSuccess);
            Assert.NotNull(result.Success);
            Assert.Equal(externalCallMessage.To, result.Success.ContractAddress);
            Assert.Equal(vmExecutionResult.Success.Result, result.Success.ExecutionResult);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
        public void Create_Contract_Success()
        {
            var contractTxData = new ContractTxData(1, 1, (Gas)1000, new byte[] { 0xAA, 0xBB, 0xCC });

            VmExecutionResult vmExecutionResult = VmExecutionResult.Ok(new object(), null);

            StateTransitionResult stateTransitionResult = StateTransitionResult.Ok((Gas)100, uint160.One, vmExecutionResult.Success.Result);

            var    fixture  = new ExecutorFixture(contractTxData);
            IState snapshot = fixture.State.Object.Snapshot();

            fixture.StateProcessor
            .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCreateMessage>()))
            .Returns(stateTransitionResult);

            IStateRepository trackedMock = Mock.Of <IStateRepository>();

            fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock);

            var sut = new LocalExecutor(
                fixture.LoggerFactory,
                fixture.CallDataSerializer.Object,
                fixture.ContractStateRoot.Object,
                fixture.StateFactory.Object,
                fixture.StateProcessor.Object,
                fixture.ContractPrimitiveSerializer.Object);

            ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext);

            fixture.CallDataSerializer.Verify(s => s.Deserialize(fixture.ContractTransactionContext.Data), Times.Once);

            fixture.StateFactory.Verify(sf => sf
                                        .Create(
                                            trackedMock,
                                            It.IsAny <IBlock>(),
                                            fixture.ContractTransactionContext.TxOutValue,
                                            fixture.ContractTransactionContext.TransactionHash),
                                        Times.Once);

            // We only apply the message to the snapshot.
            fixture.StateProcessor.Verify(sm => sm.Apply(snapshot, It.IsAny <ExternalCreateMessage>()), Times.Once);

            // Should never transition to the snapshot.
            fixture.State.Verify(sm => sm.TransitionTo(snapshot), Times.Never);

            // Should never save on the state
            fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never);

            Assert.Null(result.ErrorMessage);
            Assert.False(result.Revert);
            Assert.Equal(fixture.State.Object.InternalTransfers, result.InternalTransfers);
            Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed);
            Assert.Equal(stateTransitionResult.Success.ExecutionResult, result.Return);
            Assert.Equal(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs);
        }
        public void ExternalCall_Vm_Error()
        {
            var gasLimit          = (Gas)(GasPriceList.BaseCost + 100000);
            var vmExecutionResult = VmExecutionResult.Error(new ContractErrorMessage("Error"));

            // Code must have a length to pass precondition checks.
            var code     = new byte[1];
            var typeName = "Test";

            var externalCallMessage = new ExternalCallMessage(
                uint160.Zero,
                uint160.Zero,
                0,
                gasLimit,
                new MethodCall("Test")
                );

            this.contractStateRoot
            .Setup(sr => sr.GetCode(externalCallMessage.To))
            .Returns(code);

            this.contractStateRoot
            .Setup(sr => sr.GetContractType(externalCallMessage.To))
            .Returns(typeName);

            this.vm.Setup(v =>
                          v.ExecuteMethod(It.IsAny <ISmartContractState>(), externalCallMessage.Method, code, typeName))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, externalCallMessage);

            this.contractStateRoot.Verify(sr => sr.GetCode(externalCallMessage.To), Times.Once);

            this.contractStateRoot.Verify(sr => sr.GetContractType(externalCallMessage.To), Times.Once);

            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <GasMeter>(), externalCallMessage.To, externalCallMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), externalCallMessage.Method, code, typeName),
                Times.Once);

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Equal(result.Error.VmError, vmExecutionResult.ErrorMessage);
            Assert.Equal(StateTransitionErrorKind.VmError, result.Error.Kind);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
Ejemplo n.º 14
0
        public void VM_ExecuteContract_OutOfGas()
        {
            ContractCompilationResult compilationResult = ContractCompiler.Compile(
                @"
using System;
using Stratis.SmartContracts;

public class Contract : SmartContract
{
    public Contract(ISmartContractState state) : base(state) {}
}
");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            byte[] codeHash = HashHelper.Keccak256(contractExecutionCode);

            // Set up the state with an empty gasmeter so that out of gas occurs
            var contractState = Mock.Of <ISmartContractState>(s =>
                                                              s.Block == Mock.Of <IBlock>(b => b.Number == 1 && b.Coinbase == this.TestAddress) &&
                                                              s.Message == new Message(this.TestAddress, this.TestAddress, 0) &&
                                                              s.PersistentState == new PersistentState(
                                                                  new TestPersistenceStrategy(this.state),
                                                                  this.context.Serializer, this.TestAddress.ToUint160()) &&
                                                              s.Serializer == this.context.Serializer &&
                                                              s.ContractLogger == new ContractLogHolder() &&
                                                              s.InternalTransactionExecutor == Mock.Of <IInternalTransactionExecutor>() &&
                                                              s.InternalHashHelper == new InternalHashHelper() &&
                                                              s.GetBalance == new Func <ulong>(() => 0));

            var emptyGasMeter    = new GasMeter((RuntimeObserver.Gas) 0);
            var executionContext = new ExecutionContext(new Observer(emptyGasMeter, new MemoryMeter(100_000)));

            VmExecutionResult result = this.vm.Create(
                this.state,
                contractState,
                executionContext,
                contractExecutionCode,
                null);

            CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash));

            // Check that it's been cached, even though we ran out of gas.
            Assert.NotNull(cachedAssembly);

            // Check that the observer has been reset.
            Assert.Null(cachedAssembly.Assembly.GetObserver());

            Assert.False(result.IsSuccess);
            Assert.Equal(VmExecutionErrorKind.OutOfGas, result.Error.ErrorKind);
        }
        public void VM_CreateContract_WithParameters()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/Auction.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            var    methodParameters      = new object[] { (ulong)5 };

            VmExecutionResult result = this.vm.Create(this.state, this.contractState, contractExecutionCode, methodParameters);

            Assert.Null(result.ExecutionException);
        }
        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 gasLimit = (Gas)500000;
            var gasMeter = new GasMeter(gasLimit);
            var internalTxExecutorFactory =
                new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);

            var vm = new ReflectionVirtualMachine(this.validator, internalTxExecutorFactory, this.loggerFactory, this.network, this.addressGenerator);

            uint160 address = TestAddress.ToUint160(this.network);

            var callData = new CallData(gasLimit, address, "TestMethod", new object[] { 1 });

            var transactionContext = new TransactionContext(uint256.One, 0, address, address, 0);

            this.repository.SetCode(callData.ContractAddress, originalAssemblyBytes);
            this.repository.SetContractType(callData.ContractAddress, "Test");

            VmExecutionResult result = vm.ExecuteMethod(gasMeter,
                                                        this.repository,
                                                        callData,
                                                        transactionContext);

            Assert.Equal((ulong)aimGasAmount, result.GasConsumed);
        }
        public void VM_CreateContract_WithParameters()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult =
                SmartContractCompiler.CompileFile("SmartContracts/Auction.cs");

            Assert.True(compilationResult.Success);
            byte[] contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //Set the calldata for the transaction----------
            var methodParameters = new object[] { (ulong)5 };
            var callData         = new CreateData((Gas)5000000, contractExecutionCode, methodParameters);

            Money value = Money.Zero;
            //-------------------------------------------------------

            var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()));
            IContractStateRepository track = repository.StartTracking();

            var gasMeter = new GasMeter(callData.GasLimit);

            var internalTxExecutorFactory =
                new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);

            var vm = new ReflectionVirtualMachine(this.validator, internalTxExecutorFactory, this.loggerFactory, this.network, this.addressGenerator);

            var transactionContext = new TransactionContext(
                txHash: uint256.One,
                blockHeight: 1,
                coinbase: TestAddress.ToUint160(this.network),
                sender: TestAddress.ToUint160(this.network),
                amount: value
                );

            VmExecutionResult result = vm.Create(gasMeter,
                                                 repository,
                                                 callData,
                                                 transactionContext);

            track.Commit();

            var endBlockValue = track.GetStorageValue(result.NewContractAddress,
                                                      Encoding.UTF8.GetBytes("EndBlock"));

            Assert.Equal(6, BitConverter.ToInt16(endBlockValue, 0));
            Assert.Equal(TestAddress.ToUint160(this.network).ToBytes(), track.GetStorageValue(result.NewContractAddress, Encoding.UTF8.GetBytes("Owner")));
        }
        public void VM_ExecuteContract_WithParameters()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            var    methodParameters      = new object[] { (int)5 };
            var    callData = new MethodCall("OneParamTest", methodParameters);

            VmExecutionResult result = this.vm.ExecuteMethod(this.contractState,
                                                             callData,
                                                             contractExecutionCode, "StorageTest");

            Assert.Null(result.ExecutionException);
            Assert.Equal(methodParameters[0], result.Result);
        }
        public void VM_ExecuteContract_WithoutParameters()
        {
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;

            var callData = new MethodCall("NoParamsTest");

            VmExecutionResult result = this.vm.ExecuteMethod(this.contractState,
                                                             callData,
                                                             contractExecutionCode, "StorageTest");

            Assert.Null(result.ExecutionException);
            Assert.True((bool)result.Result);
        }
        public void VM_ExecuteContract_WithParameters()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTestWithParameters.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //Set the calldata for the transaction----------
            var   methodParameters = new object[] { (short)5 };
            var   callData         = new CallData((Gas)5000000, new uint160(1), "StoreData", methodParameters);
            Money value            = Money.Zero;
            //-------------------------------------------------------

            var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()));
            IContractStateRepository track = repository.StartTracking();

            var gasMeter = new GasMeter(callData.GasLimit);

            var internalTxExecutorFactory =
                new InternalTransactionExecutorFactory(this.keyEncodingStrategy, this.loggerFactory, this.network);
            var vm = new ReflectionVirtualMachine(this.validator, internalTxExecutorFactory, this.loggerFactory, this.network, this.addressGenerator);

            uint160 address = TestAddress.ToUint160(this.network);

            var transactionContext = new TransactionContext(uint256.One, 1, address, address, value);

            repository.SetCode(callData.ContractAddress, contractExecutionCode);
            repository.SetContractType(callData.ContractAddress, "StorageTestWithParameters");

            VmExecutionResult result = vm.ExecuteMethod(gasMeter,
                                                        repository,
                                                        callData,
                                                        transactionContext);

            track.Commit();

            Assert.Equal(5, BitConverter.ToInt16(track.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("orders")), 0));
            Assert.Equal(5, BitConverter.ToInt16(repository.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("orders")), 0));
        }
        public void VM_ExecuteContract_OutOfGas()
        {
            ContractCompilationResult compilationResult = ContractCompiler.Compile(
                @"
using System;
using Stratis.SmartContracts;

public class Contract : SmartContract
{
    public Contract(ISmartContractState state) : base(state) {}
}
");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;

            // Set up the state with an empty gasmeter so that out of gas occurs
            var contractState = Mock.Of <ISmartContractState>(s =>
                                                              s.Block == Mock.Of <IBlock>(b => b.Number == 1 && b.Coinbase == this.TestAddress) &&
                                                              s.Message == new Message(this.TestAddress, this.TestAddress, 0) &&
                                                              s.PersistentState == new PersistentState(
                                                                  new TestPersistenceStrategy(this.state),
                                                                  this.context.Serializer, this.TestAddress.ToUint160()) &&
                                                              s.Serializer == this.context.Serializer &&
                                                              s.ContractLogger == new ContractLogHolder() &&
                                                              s.InternalTransactionExecutor == Mock.Of <IInternalTransactionExecutor>() &&
                                                              s.InternalHashHelper == new InternalHashHelper() &&
                                                              s.GetBalance == new Func <ulong>(() => 0));

            var emptyGasMeter = new GasMeter((Gas)0);

            VmExecutionResult result = this.vm.Create(
                this.state,
                contractState,
                emptyGasMeter,
                contractExecutionCode,
                null);

            Assert.False(result.IsSuccess);
            Assert.Equal(VmExecutionErrorKind.OutOfGas, result.Error.ErrorKind);
        }
        public void ExternalCreate_Success()
        {
            var newContractAddress = uint160.One;
            var vmExecutionResult  = VmExecutionResult.Ok(true, "Test");

            var externalCreateMessage = new ExternalCreateMessage(
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000),
                new byte[0],
                null
                );

            this.vm.Setup(v => v.Create(this.contractStateRoot.Object, It.IsAny <ISmartContractState>(), externalCreateMessage.Code, externalCreateMessage.Parameters, null))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);
            state.Setup(s => s.GenerateAddress(It.IsAny <IAddressGenerator>())).Returns(newContractAddress);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, externalCreateMessage);

            state.Verify(s => s.AddInitialTransfer(It.Is <TransferInfo>(t => t.Value == externalCreateMessage.Amount && t.To == newContractAddress)));

            state.Verify(s => s.GenerateAddress(this.addressGenerator.Object), Times.Once);

            this.contractStateRoot.Verify(s => s.CreateAccount(newContractAddress), Times.Once);

            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <GasMeter>(), newContractAddress, externalCreateMessage, this.contractStateRoot.Object));

            this.vm.Verify(v => v.Create(this.contractStateRoot.Object, It.IsAny <ISmartContractState>(), externalCreateMessage.Code, externalCreateMessage.Parameters, null), Times.Once);

            Assert.True(result.IsSuccess);
            Assert.NotNull(result.Success);
            Assert.Equal(newContractAddress, result.Success.ContractAddress);
            Assert.Equal(vmExecutionResult.Success.Result, result.Success.ExecutionResult);
            Assert.Equal(GasPriceList.CreateCost, result.GasConsumed);
        }
        public void VM_ExecuteContract_WithoutParameters()
        {
            //Get the contract execution code------------------------
            SmartContractCompilationResult compilationResult = SmartContractCompiler.CompileFile("SmartContracts/StorageTest.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            //-------------------------------------------------------

            //Set the calldata for the transaction----------
            var callData = new CallData((Gas)5000000, new uint160(1), "StoreData");

            Money value = Money.Zero;
            //-------------------------------------------------------

            var repository = new ContractStateRepositoryRoot(new NoDeleteSource <byte[], byte[]>(new MemoryDictionarySource()));
            IContractStateRepository stateRepository = repository.StartTracking();

            var gasMeter = new GasMeter(callData.GasLimit);

            uint160 address = TestAddress.ToUint160(this.network);

            var transactionContext = new TransactionContext(uint256.One, 1, address, address, 0);

            repository.SetCode(callData.ContractAddress, contractExecutionCode);
            repository.SetContractType(callData.ContractAddress, "StorageTest");

            VmExecutionResult result = this.vm.ExecuteMethod(gasMeter,
                                                             repository,
                                                             callData,
                                                             transactionContext);

            stateRepository.Commit();

            Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), stateRepository.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("TestKey")));
            Assert.Equal(Encoding.UTF8.GetBytes("TestValue"), repository.GetStorageValue(callData.ContractAddress, Encoding.UTF8.GetBytes("TestKey")));
        }
        public void ExternalCreate_Vm_Error()
        {
            var newContractAddress = uint160.One;
            var vmExecutionResult  = VmExecutionResult.Error(new ContractErrorMessage("Error"));

            var externalCreateMessage = new ExternalCreateMessage(
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000),
                new byte[0],
                null
                );

            this.vm.Setup(v => v.Create(this.contractStateRoot.Object, It.IsAny <ISmartContractState>(), externalCreateMessage.Code, externalCreateMessage.Parameters, null))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);
            state.Setup(s => s.GenerateAddress(It.IsAny <IAddressGenerator>())).Returns(newContractAddress);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, externalCreateMessage);

            state.Verify(s => s.GenerateAddress(this.addressGenerator.Object), Times.Once);

            this.contractStateRoot.Verify(ts => ts.CreateAccount(newContractAddress), Times.Once);

            this.vm.Verify(v => v.Create(this.contractStateRoot.Object, It.IsAny <ISmartContractState>(), externalCreateMessage.Code, externalCreateMessage.Parameters, null), Times.Once);

            Assert.False(result.IsSuccess);
            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Equal(vmExecutionResult.ErrorMessage, result.Error.VmError);
            Assert.Equal(StateTransitionErrorKind.VmError, result.Error.Kind);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
Ejemplo n.º 25
0
        public void VM_ExecuteContract_ClearStorage()
        {
            ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/ClearStorage.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            byte[] codeHash = HashHelper.Keccak256(contractExecutionCode);

            var callData = new MethodCall(nameof(ClearStorage.ClearKey), new object[] { });

            uint160 contractAddress = this.contractState.Message.ContractAddress.ToUint160();

            byte[] keyToClear = Encoding.UTF8.GetBytes(ClearStorage.KeyToClear);

            // Set a value to be cleared
            this.state.SetStorageValue(contractAddress, keyToClear, new byte[] { 1, 2, 3 });

            var executionContext = new ExecutionContext(new Observer(this.gasMeter, new MemoryMeter(100_000)));

            VmExecutionResult result = this.vm.ExecuteMethod(this.contractState,
                                                             executionContext,
                                                             callData,
                                                             contractExecutionCode,
                                                             nameof(ClearStorage));

            CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash));

            // Check that it's been cached for a successful call.
            Assert.NotNull(cachedAssembly);

            // Check that the observer has been reset.
            Assert.Null(cachedAssembly.Assembly.GetObserver());

            Assert.Null(result.Error);
            Assert.Null(this.state.GetStorageValue(contractAddress, keyToClear));
        }
Ejemplo n.º 26
0
        public void VM_CreateContract_WithParameters()
        {
            ContractCompilationResult compilationResult = ContractCompiler.CompileFile("SmartContracts/Auction.cs");

            Assert.True(compilationResult.Success);

            byte[] contractExecutionCode = compilationResult.Compilation;
            byte[] codeHash = HashHelper.Keccak256(contractExecutionCode);

            var methodParameters = new object[] { (ulong)5 };
            var executionContext = new ExecutionContext(new Observer(this.gasMeter, new MemoryMeter(100_000)));

            VmExecutionResult result = this.vm.Create(this.state, this.contractState, executionContext, contractExecutionCode, methodParameters);

            CachedAssemblyPackage cachedAssembly = this.context.ContractCache.Retrieve(new uint256(codeHash));

            // Check that it's been cached.
            Assert.NotNull(cachedAssembly);

            // Check that the observer has been reset.
            Assert.Null(cachedAssembly.Assembly.GetObserver());
            Assert.True(result.IsSuccess);
            Assert.Null(result.Error);
        }
Ejemplo n.º 27
0
        public void Call_Contract_Success()
        {
            var parameters     = new object[] { };
            var contractTxData = new ContractTxData(1, 1, (RuntimeObserver.Gas) 1000, uint160.One, "TestMethod", parameters);

            VmExecutionResult vmExecutionResult = VmExecutionResult.Ok(new object(), null);

            StateTransitionResult stateTransitionResult = StateTransitionResult.Ok((RuntimeObserver.Gas) 100, uint160.One, vmExecutionResult.Success.Result);

            var    fixture  = new ExecutorFixture(contractTxData);
            IState snapshot = fixture.State.Object.Snapshot();

            fixture.StateProcessor
            .Setup(s => s.Apply(snapshot, It.IsAny <ExternalCallMessage>()))
            .Returns(stateTransitionResult);

            IStateRepository trackedMock = Mock.Of <IStateRepository>();

            fixture.ContractStateRoot.Setup(s => s.StartTracking()).Returns(trackedMock);

            var sut = new LocalExecutor(
                fixture.LoggerFactory,
                fixture.CallDataSerializer.Object,
                fixture.ContractStateRoot.Object,
                fixture.StateFactory.Object,
                fixture.StateProcessor.Object,
                fixture.ContractPrimitiveSerializer.Object);

            ILocalExecutionResult result = sut.Execute(fixture.ContractTransactionContext.BlockHeight,
                                                       fixture.ContractTransactionContext.Sender,
                                                       fixture.ContractTransactionContext.TxOutValue,
                                                       contractTxData);

            // Local executor used a tracked staterepository
            fixture.StateFactory.Verify(sf => sf
                                        .Create(
                                            trackedMock,
                                            It.IsAny <IBlock>(),
                                            fixture.ContractTransactionContext.TxOutValue,
                                            It.IsAny <uint256>()),
                                        Times.Once);

            // We only apply the message to the snapshot.
            fixture.StateProcessor.Verify(sm => sm.Apply(snapshot, It.Is <ExternalCallMessage>(m =>
                                                                                               m.Method.Name == contractTxData.MethodName &&
                                                                                               m.Method.Parameters == contractTxData.MethodParameters &&
                                                                                               m.Amount == fixture.ContractTransactionContext.TxOutValue &&
                                                                                               m.From == fixture.ContractTransactionContext.Sender &&
                                                                                               m.To == contractTxData.ContractAddress)), Times.Once);

            // Should never transition to the snapshot.
            fixture.State.Verify(sm => sm.TransitionTo(snapshot), Times.Never);

            // Should never save on the state
            fixture.ContractStateRoot.Verify(sr => sr.Commit(), Times.Never);

            Assert.Null(result.ErrorMessage);
            Assert.False(result.Revert);
            Assert.Equal <IReadOnlyList <TransferInfo> >(fixture.State.Object.InternalTransfers, result.InternalTransfers);
            Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed);
            Assert.Equal(stateTransitionResult.Success.ExecutionResult, result.Return);
            Assert.Equal <IList <Log> >(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs);
        }
        public void Create_Contract_Success()
        {
            uint160     newContractAddress = uint160.One;
            var         gasConsumed        = (Gas)100;
            var         code           = new byte[] { 0xAA, 0xBB, 0xCC };
            var         contractTxData = new ContractTxData(1, 1, (Gas)1000, code);
            var         refund         = new Money(0);
            const ulong mempoolFee     = 2UL; // MOQ doesn't like it when you use a type with implicit conversions (Money)
            ISmartContractTransactionContext context = Mock.Of <ISmartContractTransactionContext>(c =>
                                                                                                  c.Data == code &&
                                                                                                  c.MempoolFee == mempoolFee &&
                                                                                                  c.Sender == uint160.One);

            var            logger        = new Mock <ILogger>();
            ILoggerFactory loggerFactory = Mock.Of <ILoggerFactory>
                                               (l => l.CreateLogger(It.IsAny <string>()) == logger.Object);

            var serializer = new Mock <ICallDataSerializer>();

            serializer
            .Setup(s => s.Deserialize(It.IsAny <byte[]>()))
            .Returns(Result.Ok(contractTxData));

            var contractPrimitiveSerializer = new Mock <IContractPrimitiveSerializer>();

            var vmExecutionResult =
                VmExecutionResult.CreationSuccess(
                    newContractAddress,
                    new List <TransferInfo>(),
                    gasConsumed,
                    null,
                    null);

            var state             = new Mock <IContractState>();
            var transferProcessor = new Mock <ISmartContractResultTransferProcessor>();

            (Money refund, List <TxOut>)refundResult = (refund, new List <TxOut>());
            var refundProcessor = new Mock <ISmartContractResultRefundProcessor>();

            refundProcessor
            .Setup(r => r.Process(
                       contractTxData,
                       mempoolFee,
                       context.Sender,
                       vmExecutionResult.GasConsumed,
                       vmExecutionResult.ExecutionException))
            .Returns(refundResult);

            var vm = new Mock <ISmartContractVirtualMachine>();

            vm.Setup(v => v.Create(It.Is <IGasMeter>(x => x.GasConsumed == GasPriceList.BaseCost),
                                   It.IsAny <IContractState>(),
                                   It.IsAny <ICreateData>(),
                                   It.IsAny <ITransactionContext>(),
                                   It.IsAny <string>()))
            .Returns(vmExecutionResult);

            var sut = new Executor(
                loggerFactory,
                contractPrimitiveSerializer.Object,
                serializer.Object,
                state.Object,
                refundProcessor.Object,
                transferProcessor.Object,
                vm.Object
                );

            sut.Execute(context);

            serializer.Verify(s => s.Deserialize(code), Times.Once);

            vm.Verify(v =>
                      v.Create(
                          It.IsAny <IGasMeter>(),
                          state.Object,
                          contractTxData,
                          It.IsAny <TransactionContext>(),
                          It.IsAny <string>()),
                      Times.Once);

            transferProcessor.Verify(t => t
                                     .Process(
                                         state.Object,
                                         vmExecutionResult.NewContractAddress,
                                         It.IsAny <ISmartContractTransactionContext>(),
                                         vmExecutionResult.InternalTransfers,
                                         false),
                                     Times.Once);

            refundProcessor.Verify(t => t
                                   .Process(
                                       contractTxData,
                                       mempoolFee,
                                       context.Sender,
                                       vmExecutionResult.GasConsumed,
                                       vmExecutionResult.ExecutionException),
                                   Times.Once);

            state.Verify(s => s.Commit(), Times.Once);
            state.Verify(s => s.Rollback(), Times.Never);
        }
Ejemplo n.º 29
0
        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);
        }
        public void InternalCall_Success()
        {
            // The difference between an internal and an external call:
            // - Internal call performs a balance check before execution
            // - Internal call appends a new internal transfer if successful
            var vmExecutionResult = VmExecutionResult.Success(true, "Test");
            var code     = new byte[1];
            var typeName = "Test";

            var internalCallMessage = new InternalCallMessage(
                uint160.One,
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000),
                new MethodCall("Test", new object[] {})
                );

            this.contractStateRoot
            .Setup(sr => sr.GetCode(internalCallMessage.To))
            .Returns(code);

            this.contractStateRoot
            .Setup(sr => sr.GetContractType(internalCallMessage.To))
            .Returns(typeName);

            this.vm.Setup(v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), internalCallMessage.Method, code, typeName))
            .Returns(vmExecutionResult);

            var state = new Mock <IState>();

            // Return the sent amount + 1
            state.Setup(s => s.GetBalance(internalCallMessage.From)).Returns(internalCallMessage.Amount + 1);

            state.SetupGet(s => s.ContractState).Returns(this.contractStateRoot.Object);

            var stateProcessor = new StateProcessor(this.vm.Object, this.addressGenerator.Object);

            StateTransitionResult result = stateProcessor.Apply(state.Object, internalCallMessage);

            // Verify we check the balance of the sender first
            state.Verify(s => s.GetBalance(internalCallMessage.From));

            // Verify we get the code from the destination address' code cache
            this.contractStateRoot.Verify(s => s.GetCode(internalCallMessage.To), Times.Once);

            // Verify we set up the smart contract state
            state.Verify(s => s.CreateSmartContractState(state.Object, It.IsAny <GasMeter>(), internalCallMessage.To, internalCallMessage, this.contractStateRoot.Object));

            // Verify the VM was invoked
            this.vm.Verify(v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), internalCallMessage.Method, code, typeName), Times.Once);

            // Verify the value was added to the internal transfer list
            state.Verify(s => s.AddInternalTransfer(It.Is <TransferInfo>(t => t.From == internalCallMessage.From &&
                                                                         t.To == internalCallMessage.To &&
                                                                         t.Value == internalCallMessage.Amount)));

            Assert.True(result.IsSuccess);
            Assert.NotNull(result.Success);
            Assert.Equal(internalCallMessage.To, result.Success.ContractAddress);
            Assert.Equal(vmExecutionResult.Result, result.Success.ExecutionResult);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }