Skip to content

Commit

Permalink
PLAT-406: VCallRequest fail with error if interference==intolerable a…
Browse files Browse the repository at this point in the history
…nd runner change state (#569)

VCallRequest must fail with error if interference==intolerable and runner change object state
  • Loading branch information
MikhailZhukov authored Jul 23, 2020
1 parent 9141aec commit 02d09c5
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 113 deletions.
9 changes: 7 additions & 2 deletions ledger-core/virtual/execute/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -802,8 +802,9 @@ func (s *SMExecute) stepSaveNewObject(ctx smachine.ExecutionContext) smachine.St
class reference.Global
)

if s.intolerableCall() {
s.executionNewState.Result = requestresult.New(executionNewState.Result(), executionNewState.ObjectReference())
if s.isIntolerableCallChangeState() {
s.prepareExecutionError(throw.E("intolerable call trying to change object state"))
return ctx.Jump(s.stepSendCallResult)
}

if s.deactivate {
Expand Down Expand Up @@ -852,6 +853,10 @@ func (s *SMExecute) stepSaveNewObject(ctx smachine.ExecutionContext) smachine.St
return ctx.Jump(s.stepSendCallResult)
}

func (s *SMExecute) isIntolerableCallChangeState() bool {
return s.intolerableCall() && (s.deactivate || s.executionNewState.Result.Type() != requestresult.SideEffectNone)
}

func (s *SMExecute) stepAwaitSMCallSummary(ctx smachine.ExecutionContext) smachine.StateUpdate {
syncAccessor, ok := callsummary.GetSummarySMSyncAccessor(ctx, s.execution.Object)

Expand Down
1 change: 1 addition & 0 deletions ledger-core/virtual/execute/execute.plantuml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ T01_S030 --> T01_S031
state "stepSaveNewObject" as T01_S028
T01_S028 : SMExecute
T01_S028 --[dotted]> T01_S016
T01_S028 --> T01_S032 : [(...).isIntolerableCallChangeState()]
T01_S028 --> T01_S032 : [(...).migrationHappened||s.newObjectDescriptor==nil]
T01_S028 --> T01_S028 : [!stepUpdate.IsEmpty()]
T01_S028 --> T01_S032
Expand Down
21 changes: 8 additions & 13 deletions ledger-core/virtual/integration/deduplication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,10 @@ func TestDeduplication_MethodUsingPrevVE(t *testing.T) {
executeDone := suite.server.Journal.WaitStopOf(&execute.SMExecute{}, 1)

suite.switchPulse(ctx)
suite.generateClass(ctx)
suite.generateCaller(ctx)
suite.generateObjectRef(ctx)
suite.generateOutgoing(ctx)
suite.generateClass()
suite.generateCaller()
suite.generateObjectRef()
suite.generateOutgoing()

suite.setMessageCheckers(ctx, t, test)
suite.setRunnerMock()
Expand Down Expand Up @@ -502,14 +502,14 @@ func (s *deduplicateMethodUsingPrevVETest) getP1() pulse.Number {
return s.p1
}

func (s *deduplicateMethodUsingPrevVETest) generateCaller(ctx context.Context) {
func (s *deduplicateMethodUsingPrevVETest) generateCaller() {
s.mu.Lock()
defer s.mu.Unlock()

s.caller = reference.NewSelf(gen.UniqueLocalRefWithPulse(s.p1))
}

func (s *deduplicateMethodUsingPrevVETest) generateObjectRef(ctx context.Context) {
func (s *deduplicateMethodUsingPrevVETest) generateObjectRef() {
p := s.getP1()

s.mu.Lock()
Expand All @@ -518,7 +518,7 @@ func (s *deduplicateMethodUsingPrevVETest) generateObjectRef(ctx context.Context
s.object = reference.NewSelf(gen.UniqueLocalRefWithPulse(p))
}

func (s *deduplicateMethodUsingPrevVETest) generateOutgoing(ctx context.Context) {
func (s *deduplicateMethodUsingPrevVETest) generateOutgoing() {
p := s.getP1()

s.mu.Lock()
Expand All @@ -527,7 +527,7 @@ func (s *deduplicateMethodUsingPrevVETest) generateOutgoing(ctx context.Context)
s.outgoing = reference.NewRecordOf(s.caller, gen.UniqueLocalRefWithPulse(p))
}

func (s *deduplicateMethodUsingPrevVETest) generateClass(ctx context.Context) {
func (s *deduplicateMethodUsingPrevVETest) generateClass() {
s.mu.Lock()
defer s.mu.Unlock()

Expand Down Expand Up @@ -703,12 +703,7 @@ func (s *deduplicateMethodUsingPrevVETest) setRunnerMock() {
isolation := contract.MethodIsolation{Interference: contract.CallIntolerable, State: contract.CallDirty}
s.runnerMock.AddExecutionClassify("SomeMethod", isolation, nil)

newObjDescriptor := descriptor.NewObject(
reference.Global{}, reference.Local{}, s.getClass(), []byte(""),
)

requestResult := requestresult.New([]byte("execution"), gen.UniqueGlobalRef())
requestResult.SetAmend(newObjDescriptor, []byte("new memory"))

executionMock := s.runnerMock.AddExecutionMock("SomeMethod")
executionMock.AddStart(func(ctx execution.Context) {
Expand Down
25 changes: 16 additions & 9 deletions ledger-core/virtual/integration/method_pulse_change_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import (
"github.com/insolar/assured-ledger/ledger-core/pulse"
"github.com/insolar/assured-ledger/ledger-core/reference"
"github.com/insolar/assured-ledger/ledger-core/runner/execution"
"github.com/insolar/assured-ledger/ledger-core/runner/executor/common/foundation"
"github.com/insolar/assured-ledger/ledger-core/runner/requestresult"
commontestutils "github.com/insolar/assured-ledger/ledger-core/testutils"
commonTestUtils "github.com/insolar/assured-ledger/ledger-core/testutils"
"github.com/insolar/assured-ledger/ledger-core/testutils/gen"
"github.com/insolar/assured-ledger/ledger-core/testutils/predicate"
"github.com/insolar/assured-ledger/ledger-core/testutils/runner/logicless"
Expand Down Expand Up @@ -69,7 +70,7 @@ func TestVirtual_Method_PulseChanged(t *testing.T) {

for _, test := range table {
t.Run(test.name, func(t *testing.T) {
defer commontestutils.LeakTester(t)
defer commonTestUtils.LeakTester(t)

mc := minimock.NewController(t)

Expand Down Expand Up @@ -200,7 +201,13 @@ func TestVirtual_Method_PulseChanged(t *testing.T) {
})
typedChecker.VCallResult.Set(func(res *payload.VCallResult) bool {
assert.Equal(t, object, res.Callee)
assert.Equal(t, []byte("call result"), res.ReturnArguments)
if test.isolation == intolerableFlags() && test.withSideEffect {
contractErr, sysErr := foundation.UnmarshalMethodResult(res.ReturnArguments)
require.NoError(t, sysErr)
require.Equal(t, "intolerable call trying to change object state", contractErr.Error())
} else {
assert.Equal(t, []byte("call result"), res.ReturnArguments)
}
assert.Equal(t, p1, res.CallOutgoing.GetLocal().Pulse())
assert.Equal(t, expectedToken, res.DelegationSpec)
return false
Expand Down Expand Up @@ -243,7 +250,7 @@ func TestVirtual_Method_PulseChanged(t *testing.T) {

// 2 ordered and 2 unordered calls
func TestVirtual_Method_CheckPendingsCount(t *testing.T) {
defer commontestutils.LeakTester(t)
defer commonTestUtils.LeakTester(t)

t.Log("C5104")

Expand Down Expand Up @@ -296,15 +303,15 @@ func TestVirtual_Method_CheckPendingsCount(t *testing.T) {
LatestValidatedState: &objectState,
}

payload := &payload.VStateReport{
vsrPayload := &payload.VStateReport{
Status: payload.Ready,
Object: object,
UnorderedPendingEarliestPulse: pulse.OfNow(),
ProvidedContent: content,
}

server.WaitIdleConveyor()
server.SendPayload(ctx, payload)
server.SendPayload(ctx, vsrPayload)
server.WaitActiveThenIdleConveyor()
}

Expand Down Expand Up @@ -453,7 +460,7 @@ func TestVirtual_MethodCall_IfConstructorIsPending(t *testing.T) {

for _, test := range table {
t.Run(test.name, func(t *testing.T) {
defer commontestutils.LeakTester(t)
defer commonTestUtils.LeakTester(t)

mc := minimock.NewController(t)

Expand Down Expand Up @@ -489,15 +496,15 @@ func TestVirtual_MethodCall_IfConstructorIsPending(t *testing.T) {

// create object state
{
payload := &payload.VStateReport{
vsrPayload := &payload.VStateReport{
Status: payload.Empty,
Object: object,
AsOf: p1,
OrderedPendingCount: 1,
OrderedPendingEarliestPulse: p1,
}

server.SendPayload(ctx, payload)
server.SendPayload(ctx, vsrPayload)
server.WaitActiveThenIdleConveyor()
}

Expand Down
Loading

0 comments on commit 02d09c5

Please sign in to comment.