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