Beispiel #1
0
        public void Contract_Transfer_To_Other_Contract_Balance_Error()
        {
            var contractTransferMessage = new ContractTransferMessage(
                uint160.One,
                uint160.Zero,
                10,
                (RuntimeObserver.Gas)(GasPriceList.BaseCost + 100000)
                );

            var state = new Mock <IState>();

            // Setup the balance with less than the required amount.
            state.Setup(s => s.GetBalance(contractTransferMessage.From))
            .Returns(contractTransferMessage.Amount - 1);

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

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

            state.Verify(s => s.GetBalance(contractTransferMessage.From));

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Null(result.Error.VmError);
            Assert.Equal(StateTransitionErrorKind.InsufficientBalance, result.Error.Kind);
            Assert.Equal((RuntimeObserver.Gas) 0, result.GasConsumed);
        }
        public void Execute_transitions_when_matched_superState()
        {
            var stateMachine    = getStateMachine();
            var openStateConfig = stateMachine.ConfigureState(SaleState.Open);

            stateMachine.ConfigureState(SaleState.ChangeDue).MakeSubstateOf(openStateConfig);

            var sut = new StateTransitionAutoDynamic <Sale, SaleState, SaleEvent>(stateMachine
                                                                                  , SaleState.Open
                                                                                  , _ => SaleState.Complete
                                                                                  , SaleState.Open
                                                                                  , "autoComplete"
                                                                                  , priority: 1);

            var testSale = new Sale(saleID: 2)
            {
                State = SaleState.ChangeDue
            };
            var parameters     = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, testSale);
            var previousResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay, SaleState.Open, SaleState.Open, SaleState.ChangeDue, "previousTransition");

            var result = sut.Execute(parameters, previousResult);

            Assert.True(result.WasTransitioned);
            Assert.Equal("autoComplete", result.LastTransitionName);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.ChangeDue, SaleState.ChangeDue);
            Assert.Equal(SaleState.Open, result.StartingState);
            Assert.Equal(SaleState.Complete, testSale.State);
        }
        public async Task ExecuteExitActionAsync_does_not_execute_if_cancelled()
        {
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.ChangeDue
            };
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay
                                                                                    , SaleState.Open
                                                                                    , SaleState.Open
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");
            var stateMachine = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            var openState    = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.Open, stateMachine);

            var openExitActionFired = false;

            openState.AddExitAction((sale1, _) => { openExitActionFired = true; return(Task.CompletedTask); });

            using (var cancelSource = new CancellationTokenSource())
            {
                var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, sale, cancelSource.Token);
                cancelSource.Cancel();

                await openState.ExecuteExitActionAsync(parameters, transitionResult);
            }

            Assert.False(openExitActionFired);
        }
        public async Task ExecuteReentryActionAsync_executes_ReentryAction()
        {
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.Open
            };
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.AddItem
                                                                                    , SaleState.Open
                                                                                    , SaleState.Open
                                                                                    , SaleState.Open
                                                                                    , "lastTransitionName");
            var stateMachine   = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            var openState      = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.Open, stateMachine);
            var changeDueState = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.ChangeDue, stateMachine);

            changeDueState.AddSuperstate(openState);
            var changeDueEntryActionFromOpenFired = false;

            changeDueState.AddReentryAction((sale1, _) => { changeDueEntryActionFromOpenFired = true; return(Task.CompletedTask); });
            var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, sale);

            await changeDueState.ExecuteReentryActionAsync(parameters, transitionResult);

            Assert.True(changeDueEntryActionFromOpenFired);
        }
        public void Execute_transitions_when_matched()
        {
            var notificationReceived = false;
            var stateMachine         = getStateMachine();

            stateMachine.RegisterOnTransitionedAction((sale, _) => notificationReceived = true);
            var sut = new StateTransitionAutoDynamicParameterizedAsync <Sale, SaleState, SaleEvent, string>(stateMachine
                                                                                                            , SaleState.Open
                                                                                                            , (sale, stringParam) => SaleState.Complete
                                                                                                            , SaleState.ChangeDue
                                                                                                            , "autocomplete"
                                                                                                            , 1);

            var testSale = new Sale(2)
            {
                State = SaleState.Open
            };
            var parameters     = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, testSale, request: "testParam");
            var previousResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay, SaleState.Open, SaleState.Open, SaleState.ChangeDue, "previousTransition");

            var result = sut.Execute(parameters, previousResult);

            Assert.True(result.WasTransitioned);
            Assert.Equal("autocomplete", result.LastTransitionName);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.ChangeDue, SaleState.ChangeDue);
            Assert.Equal(SaleState.Open, result.StartingState);
            Assert.Equal(SaleState.Complete, testSale.State);
            Assert.True(notificationReceived);
        }
Beispiel #6
0
        public void Call_Contract_Failure()
        {
            var parameters     = new object[] { };
            var contractTxData = new ContractTxData(1, 1, (Gas)1000, uint160.One, "TestMethod", parameters);

            StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((Gas)100, StateTransitionErrorKind.VmError);

            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);

            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.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage);
            Assert.True(result.Revert);
            Assert.Equal <IReadOnlyList <TransferInfo> >(fixture.State.Object.InternalTransfers, result.InternalTransfers);
            Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed);
            Assert.Null(result.Return);
            Assert.Equal <IList <Log> >(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs);
        }
        public async Task ExecuteAutoTransitionAsync_executes_AutoTransition_for_superState()
        {
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.ChangeDue
            };
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay
                                                                                    , SaleState.Open
                                                                                    , SaleState.Open
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");
            var stateMachine = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            IStateConfigurationInternal <Sale, SaleState, SaleEvent> openState      = stateMachine.ConfigureState(SaleState.Open) as IStateConfigurationInternal <Sale, SaleState, SaleEvent>;
            IStateConfigurationInternal <Sale, SaleState, SaleEvent> changeDueState = stateMachine.ConfigureState(SaleState.ChangeDue) as IStateConfigurationInternal <Sale, SaleState, SaleEvent>;

            Debug.Assert(changeDueState != null, nameof(changeDueState) + " != null");
            changeDueState.AddSuperstate(openState);
            Debug.Assert(openState != null, nameof(openState) + " != null");
            openState.AddAutoForwardTransition(SaleEvent.ChangeGiven, SaleState.Complete, (sale1, _) => Task.FromResult(result: true));
            var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.ChangeGiven, sale);

            var autoTransitionResult = await changeDueState.ExecuteAutoTransitionAsync(parameters, transitionResult);

            Assert.True(autoTransitionResult.WasTransitioned);
            Assert.Equal(SaleState.Complete, sale.State);
            Assert.Equal(SaleState.Complete, autoTransitionResult.CurrentState);
            Assert.Equal(SaleState.ChangeDue, autoTransitionResult.PreviousState);
            Assert.Equal(SaleState.Open, autoTransitionResult.StartingState);
        }
Beispiel #8
0
        public void ExternalCall_Code_Null()
        {
            var gasLimit = (Gas)(GasPriceList.BaseCost + 100000);

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

            this.contractStateRoot
            .Setup(sr => sr.GetCode(externalCallMessage.To))
            .Returns((byte[])null);

            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);

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Null(result.Error.VmError);
            Assert.Equal(StateTransitionErrorKind.NoCode, result.Error.Kind);
            Assert.Equal((Gas)0, result.GasConsumed);
        }
        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,
                (Gas)(GasPriceList.BaseCost + 100000),
                new object[] { },
                typeName
                );

            this.vm.Setup(v =>
                          v.Create(It.IsAny <IStateRepository>(),
                                   It.IsAny <ISmartContractState>(),
                                   It.IsAny <IGasMeter>(),
                                   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 <IGasMeter>(), newContractAddress, internalCreateMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.Create(
                    this.contractStateRoot.Object,
                    It.IsAny <ISmartContractState>(),
                    It.IsAny <IGasMeter>(),
                    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);
        }
        public void InternalCall_Balance_Error()
        {
            var internalCallMessage = new InternalCallMessage(
                uint160.One,
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000),
                new MethodCall("Test", new object[] { })
                );

            var state = new Mock <IState>();

            // Setup the balance with less than the required amount.
            state.Setup(s => s.GetBalance(internalCallMessage.From))
            .Returns(internalCallMessage.Amount - 1);

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

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

            state.Verify(s => s.GetBalance(internalCallMessage.From));

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Null(result.Error.VmError);
            Assert.Equal(StateTransitionErrorKind.InsufficientBalance, result.Error.Kind);
            Assert.Equal((Gas)0, result.GasConsumed);
        }
Beispiel #11
0
        public override StateTransitionResult <TState, TTrigger> Execute(ExecutionParameters <T, TTrigger> parameters
                                                                         , StateTransitionResult <TState, TTrigger> currentResult = null)
        {
            if (!(parameters.Request is TRequest typeSafeParam))
            {
                throw new ArgumentException($"Expected a {typeof(TRequest).Name} parameter, but received a {parameters.Request?.GetType().Name ?? "null"}.");
            }

            if (currentResult != null &&
                !parameters.CancellationToken.IsCancellationRequested &&
                _startState.IsEqual(currentResult.PreviousState) &&
                (_triggerState.IsEqual(currentResult.CurrentState) ||
                 _stateMachine.IsInState(parameters.Context, _triggerState)))
            {
                StateMutator(parameters.Context, _stateFunction(parameters.Context, typeSafeParam));

                var transitioned = !StateAccessor(parameters.Context).IsEqual(_triggerState);
                var result       = GetFreshResult(parameters
                                                  , currentResult
                                                  , currentResult.StartingState
                                                  , wasCancelled: false
                                                  , transitionDefined: true
                                                  , conditionMet: transitioned);

                return(result);
            }

            return(GetFreshResult(parameters
                                  , currentResult
                                  , StateAccessor(parameters.Context)
                                  , wasCancelled: parameters.CancellationToken.IsCancellationRequested
                                  , transitionDefined: true
                                  , conditionMet: false));
        }
        public async Task ExecuteEntryActionAsync_executes_for_super_state()
        {
            var entryActionCalled = false;
            var stateMachine      = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            var openConfig        = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.Open, stateMachine);

            openConfig.AddEntryAction((sale1, _) => { entryActionCalled = true; return(Task.CompletedTask); });
            var changeDueConfig = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.ChangeDue, stateMachine);

            changeDueConfig.MakeSubStateOf(openConfig);
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.ChangeDue
            };
            var parameters       = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, sale);
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay
                                                                                    , SaleState.Open
                                                                                    , SaleState.Complete
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");

            await changeDueConfig.ExecuteEntryActionAsync(parameters, transitionResult);

            Assert.True(entryActionCalled);
        }
Beispiel #13
0
        public void ExecuteAutoTransition_executes_AutoTransition_without_previous_state()
        {
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.ChangeDue
            };
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.ChangeGiven
                                                                                    , SaleState.Open
                                                                                    , SaleState.ChangeDue
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");
            var stateMachine = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            var sut          = new StateConfiguration <Sale, SaleState, SaleEvent>(SaleState.ChangeDue, stateMachine);

            sut.AddAutoForwardTransition(SaleEvent.ChangeGiven, SaleState.Complete, sale1 => true);
            var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.ChangeGiven, sale);

            var autoTransitionResult = sut.ExecuteAutoTransition(parameters, transitionResult);

            Assert.True(autoTransitionResult.WasTransitioned);
            Assert.Equal(SaleState.Complete, sale.State);
            Assert.Equal(SaleState.Complete, autoTransitionResult.CurrentState);
            Assert.Equal(SaleState.ChangeDue, autoTransitionResult.PreviousState);
            Assert.Equal(SaleState.Open, autoTransitionResult.StartingState);
        }
Beispiel #14
0
        public void ExecuteAutoTransition_executes_AutoTransition_for_superState()
        {
            //Scenario: Sale has been paid for and goes to ChangeDue. If no change due, it should automatically transition to Complete.
            //ChangeDue is a sub-state of Open and Open has the autoForward defined for Pay.
            var sale = new Sale(saleId: 96)
            {
                State = SaleState.ChangeDue
            };

            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.AddItem
                                                                                    , SaleState.Open
                                                                                    , SaleState.Open
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");
            var stateMachine = new StateMachine <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            IStateConfigurationInternal <Sale, SaleState, SaleEvent> openState      = stateMachine.ConfigureState(SaleState.Open) as IStateConfigurationInternal <Sale, SaleState, SaleEvent>;
            IStateConfigurationInternal <Sale, SaleState, SaleEvent> changeDueState = stateMachine.ConfigureState(SaleState.ChangeDue) as IStateConfigurationInternal <Sale, SaleState, SaleEvent>;

            changeDueState?.AddSuperstate(openState);
            openState?.AddAutoForwardTransition(SaleEvent.Pay, SaleState.Complete, sale1 => true /* condition indicates no change due */);
            var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, sale);

            var autoTransitionResult = changeDueState?.ExecuteAutoTransition(parameters, transitionResult);

            Assert.True(autoTransitionResult?.WasTransitioned);
            Assert.Equal(SaleState.Complete, sale.State);
            Assert.Equal(SaleState.Complete, autoTransitionResult?.CurrentState);
            Assert.Equal(SaleState.ChangeDue, autoTransitionResult?.PreviousState);
            Assert.Equal(SaleState.Open, autoTransitionResult?.StartingState);
        }
        public async Task ExecuteExitActionAsync(ExecutionParameters <T, TTrigger> parameters
                                                 , StateTransitionResult <TState, TTrigger> currentResult)
        {
            //Is there an action based on the new state?
            if (_nextStateExitActions.TryGetValue(currentResult.CurrentState, out var action))
            {
                if (parameters.CancellationToken.IsCancellationRequested)
                {
                    return;
                }

                await action.Invoke(parameters.Context, parameters.CancellationToken)
                .ConfigureAwait(continueOnCapturedContext: false);
            }

            //Is there an action for any exit?
            if (_defaultExitAction != null)
            {
                if (parameters.CancellationToken.IsCancellationRequested)
                {
                    return;
                }

                if (_defaultExitAction != null)
                {
                    await _defaultExitAction.Invoke(parameters.Context, parameters.CancellationToken)
                    .ConfigureAwait(continueOnCapturedContext: false);
                }
            }
        }
        public async void ExecuteAsync_transitions_when_matched()
        {
            var stateMachine = getStateMachine();
            var sut          = new StateTransitionAutoDynamicAsync <Sale, SaleState, SaleEvent>(stateMachine
                                                                                                , SaleState.Open
                                                                                                , _ => SaleState.Complete
                                                                                                , SaleState.ChangeDue
                                                                                                , "autocomplete"
                                                                                                , priority: 1);

            var testSale = new Sale(saleID: 2)
            {
                State = SaleState.Open
            };
            var parameters     = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, testSale);
            var previousResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay, SaleState.Open, SaleState.Open, SaleState.ChangeDue, "previousTransition");

            var result = await sut.ExecuteAsync(parameters, previousResult);

            Assert.True(result.WasTransitioned);
            Assert.Equal("autocomplete", result.LastTransitionName);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.Complete, SaleState.Complete);
            Assert.Equal(SaleState.ChangeDue, SaleState.ChangeDue);
            Assert.Equal(SaleState.Open, result.StartingState);
            Assert.Equal(SaleState.Complete, testSale.State);
        }
Beispiel #17
0
        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.Ok(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.Success.Result, result.Success.ExecutionResult);
            Assert.Equal(GasPriceList.BaseCost, result.GasConsumed);
        }
        public void InternalCall_Code_Null()
        {
            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((byte[])null);

            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);

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

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Null(result.Error.VmError);
            Assert.Equal(StateTransitionErrorKind.NoCode, result.Error.Kind);
            Assert.Equal((Gas)GasPriceList.BaseCost, result.GasConsumed);
        }
Beispiel #19
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,
                (RuntimeObserver.Gas)(GasPriceList.BaseCost + 100000),
                new MethodCall("Test", new object[] { })
                );

            this.vm.Setup(v => v.ExecuteMethod(
                              It.IsAny <ISmartContractState>(),
                              It.IsAny <ExecutionContext>(),
                              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 <RuntimeObserver.IGasMeter>(), internalCallMessage.To, internalCallMessage, this.contractStateRoot.Object));

            this.vm.Verify(
                v => v.ExecuteMethod(
                    It.IsAny <ISmartContractState>(),
                    It.IsAny <ExecutionContext>(),
                    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 ExecuteAutoTransitionAsync_can_be_cancelled()
        {
            var stopwatch = new Stopwatch();
            var sale      = new Sale(saleID: 96)
            {
                State = SaleState.ChangeDue
            };
            var transitionResult = new StateTransitionResult <SaleState, SaleEvent>(SaleEvent.Pay
                                                                                    , SaleState.ChangeDue
                                                                                    , SaleState.ChangeDue
                                                                                    , SaleState.ChangeDue
                                                                                    , "lastTransitionName");
            var stateMachine = new StateMachineAsync <Sale, SaleState, SaleEvent>(sale1 => sale1.State, (sale1, newState) => sale1.State = newState);
            var sut          = new StateConfigurationAsync <Sale, SaleState, SaleEvent>(SaleState.ChangeDue, stateMachine);

            sut.AddAutoForwardTransition(SaleEvent.ChangeGiven, SaleState.Complete, (sale1, cancelToken) =>
            {
                do
                {
                    Task.Delay(millisecondsDelay: 99).Wait();
                } while (!cancelToken.IsCancellationRequested);

                return(Task.FromResult(result: !cancelToken.IsCancellationRequested));
            });

            using (var mutex = new Mutex(initiallyOwned: false))
                using (var cancelSource = new CancellationTokenSource())
                {
                    var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.ChangeGiven, sale, cancelSource.Token);
                    StateTransitionResult <SaleState, SaleEvent> autoTransitionResult = null;

                    Task.Factory.StartNew(async() =>
                    {
                        mutex.WaitOne();
                        autoTransitionResult = await sut.ExecuteAutoTransitionAsync(parameters, transitionResult);
                        mutex.ReleaseMutex();
                    }, TaskCreationOptions.LongRunning);

                    try
                    {
                        stopwatch.Start();
                        Task.Delay(millisecondsDelay: 2345).Wait();
                        cancelSource.Cancel();
                        mutex.WaitOne();
                    }
                    catch (Exception ex)
                    {
                        cancelSource.Cancel();
                    }

                    Assert.True(autoTransitionResult.WasCancelled);
                    Assert.False(autoTransitionResult.ConditionMet);
                    Assert.True(autoTransitionResult.TransitionDefined);
                    Assert.Equal(SaleState.ChangeDue, sale.State);
                    Assert.Equal(SaleState.ChangeDue, autoTransitionResult.CurrentState);
                }
        }
Beispiel #21
0
        public void ExecuteAsync_ConditionAsync_can_be_cancelled()
        {
            const SaleState startState = SaleState.Open;
            var             sale       = new Sale(saleID: 66)
            {
                State = startState
            };
            var sut = new StateTransitionAutoForwardParameterizedAsync <Sale, SaleState, SaleEvent, string>(
                getStateMachine()
                , SaleState.Complete
                , SaleState.Open
                , conditionAsync: (_, stringParam, cancellationToken) =>
            {
                do
                {
                    Task.Delay(millisecondsDelay: 99).Wait();
                } while (!cancellationToken.IsCancellationRequested);

                return(Task.FromResult(!cancellationToken.IsCancellationRequested));
            }
                , name: "test"
                , priority: 1);

            using (var mutex = new Mutex(initiallyOwned: false))
                using (var cancelSource = new CancellationTokenSource())
                {
                    StateTransitionResult <SaleState, SaleEvent> result = null;

                    var parameters = new ExecutionParameters <Sale, SaleEvent>(SaleEvent.Pay, sale, cancellationToken: cancelSource.Token, request: "test");
                    Task.Factory.StartNew(async() =>
                    {
                        mutex.WaitOne();
                        result = await sut.ExecuteAsync(parameters, getDummyResult());
                        mutex.ReleaseMutex();
                    }, TaskCreationOptions.LongRunning);

                    try
                    {
                        Task.Delay(2222).Wait();

                        cancelSource.Cancel();
                    }
                    catch
                    {
                        cancelSource.Cancel();
                    }

                    mutex.WaitOne();

                    Assert.True(result.WasCancelled);
                    Assert.Equal(startState, sale.State);
                    Assert.Equal(startState, result.CurrentState);
                    Assert.False(result.ConditionMet);
                    Assert.True(result.TransitionDefined);
                    Assert.True(result.TransitionDefined);
                }
        }
        public void Contract_Transfer_To_Other_Contract_VM_Error()
        {
            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 contractTransferMessage = new ContractTransferMessage(
                uint160.One,
                uint160.Zero,
                10,
                (Gas)(GasPriceList.BaseCost + 100000)
                );

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

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

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

            var state = new Mock <IState>();

            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);

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

            this.vm.Verify(
                v => v.ExecuteMethod(
                    It.IsAny <ISmartContractState>(),
                    contractTransferMessage.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);
        }
        public void Create_Contract_Failure()
        {
            var contractTxData = new ContractTxData(1, 1, (Gas)1000, new byte[] { 0xAA, 0xBB, 0xCC });

            StateTransitionResult stateTransitionResult = StateTransitionResult.Fail((Gas)100, StateTransitionErrorKind.VmError);

            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.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(fixture.State.Object.Snapshot(),
                                                         It.Is <ExternalCreateMessage>(m =>
                                                                                       m.Code == contractTxData.ContractExecutionCode &&
                                                                                       m.Parameters == contractTxData.MethodParameters)), Times.Once);

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

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

            Assert.Equal(stateTransitionResult.Error.VmError, result.ErrorMessage);
            Assert.True(result.Revert);
            Assert.Equal(fixture.State.Object.InternalTransfers, result.InternalTransfers);
            Assert.Equal(stateTransitionResult.GasConsumed, result.GasConsumed);
            Assert.Null(result.Return);
            Assert.Equal(fixture.State.Object.GetLogs(fixture.ContractPrimitiveSerializer.Object), result.Logs);
        }
        public override StateTransitionResult <TState, TTrigger> Execute(ExecutionParameters <T, TTrigger> parameters
                                                                         , StateTransitionResult <TState, TTrigger> currentResult = null)
        {
            if (!(parameters.Request is TParam typeSafeParam))
            {
                throw new ArgumentException($"Expected a {typeof(TParam).Name} parameter, but received a {parameters.Request?.GetType().Name ?? "null"}.");
            }

            return(ExecutePrim(parameters, currentResult, Condition(parameters.Context, typeSafeParam)));
        }
        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 Call_Out_Of_Gas_Error()
        {
            var vmExecutionResult = VmExecutionResult.Fail(VmExecutionErrorKind.OutOfGas, "Error");

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

            var callMessage = new ExternalCallMessage(
                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>(),
                              callMessage.Method,
                              code,
                              null))
            .Returns(vmExecutionResult);

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

            var state = new Mock <IState>();

            state.Setup(s => s.GetBalance(callMessage.From))
            .Returns(callMessage.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, callMessage);

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

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

            Assert.True(result.IsFailure);
            Assert.NotNull(result.Error);
            Assert.Equal(result.Error.VmError, vmExecutionResult.Error.Message);
            Assert.Equal(StateTransitionErrorKind.OutOfGas, result.Error.Kind);
        }
Beispiel #27
0
 public KeyValuePair <StateTransitionResult, StateTransition> CheckTransitions(MonoBehaviour origin)
 {
     foreach (StateTransition transition in Transitions)
     {
         StateTransitionResult result = transition.Transition(origin, this);
         if (result == StateTransitionResult.NO_ACTION)
         {
             continue;
         }
         return(new KeyValuePair <StateTransitionResult, StateTransition>(result, transition));
     }
     return(new KeyValuePair <StateTransitionResult, StateTransition>(StateTransitionResult.NO_ACTION, new StateTransition()));
 }
        public void Contract_Transfer_To_Other_P2PKH_Success()
        {
            // There is no code at the destination address, which causes a regular P2PKH transaction to be created
            var emptyCode = new byte[0];

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

            // No code should be returned
            this.contractStateRoot
            .Setup(sr => sr.GetCode(contractTransferMessage.To))
            .Returns(emptyCode);

            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 the VM was NOT invoked
            this.vm.Verify(v => v.ExecuteMethod(It.IsAny <ISmartContractState>(), It.IsAny <MethodCall>(), It.IsAny <byte[]>(), It.IsAny <string>()), Times.Never);

            // 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.Null(result.Success.ExecutionResult);

            // No gas is consumed
            Assert.Equal((Gas)0, result.GasConsumed);
        }
        public override StateTransitionResult <TState, TTrigger> Execute(ExecutionParameters <T, TTrigger> parameters
                                                                         , StateTransitionResult <TState, TTrigger> currentResult = null)
        {
            if (_stateMachine.IsInState(parameters.Context, _triggerState))
            {
                return(base.Execute(parameters, currentResult));
            }

            return(GetFreshResult(parameters
                                  , currentResult
                                  , StateAccessor(parameters.Context)
                                  , wasCancelled: false
                                  , transitionDefined: true
                                  , conditionMet: false));
        }
        public void ExecuteExitAction(T context, StateTransitionResult <TState, TTrigger> currentResult)
        {
            //Is there an action based on the new state?
            if (_nextStateExitActions.TryGetValue(currentResult.CurrentState, out var action))
            {
                action.Invoke(context);
            }

            //Is there an action for any exit?
            _defaultExitAction?.Invoke(context);

            if (_superstateConfig != null && !IsSubstateOf(currentResult.CurrentState))
            {
                _superstateConfig.ExecuteExitAction(context, currentResult);
            }
        }