Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions integrationTests/json/scenariosTestCommon.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ func (mtb *ScenariosTestBuilder) CheckNoError() *ScenariosTestBuilder {
return mtb
}

// Teardown is a placeholder for now
func (mtb *ScenariosTestBuilder) Teardown() {
}

// RequireError does an assert for the containing error
func (mtb *ScenariosTestBuilder) RequireError(expectedErrorMsg string) *ScenariosTestBuilder {
require.EqualError(mtb.t, mtb.currentError, expectedErrorMsg)
Expand Down
51 changes: 51 additions & 0 deletions mock/context/vmHostMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,66 @@
return nil
}

ExecuteOnDestContextCalled func(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, bool, error)

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / test (1.23.6, macos-13)

syntax error: non-declaration statement outside function body

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / test (1.23.6, ubuntu-latest)

syntax error: non-declaration statement outside function body

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

expected declaration, found ExecuteOnDestContextCalled (typecheck)

Check failure on line 125 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body
}

Check failure on line 126 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / test (1.23.6, macos-13)

syntax error: non-declaration statement outside function body

Check failure on line 126 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / test (1.23.6, ubuntu-latest)

syntax error: non-declaration statement outside function body

Check failure on line 126 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body) (typecheck)

Check failure on line 126 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body) (typecheck)

Check failure on line 126 in mock/context/vmHostMock.go

View workflow job for this annotation

GitHub Actions / golangci linter

syntax error: non-declaration statement outside function body (typecheck)

// ExecuteOnDestContext mocked method
func (host *VMHostMock) ExecuteOnDestContext(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, bool, error) {
if host.ExecuteOnDestContextCalled != nil {
return host.ExecuteOnDestContextCalled(input)
}

if host.Err != nil {
return nil, true, host.Err
}
host.StoreInput(input)
return host.GetNextVMOutput(), true, nil
}

// ExecuteOnDestContext -
func (vmh *VMHostMock) ExecuteOnDestContext(gasLimit uint64, scAddress, callerAddress, calleeAddress []byte, value *big.Int, input []byte, readOnly bool) (vmOutput *vm.VMOutput, err error) {
if vmh.ExecuteOnDestContextCalled != nil {
return vmh.ExecuteOnDestContextCalled(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
if vmh.ExecuteOnDestContextCallBack != nil {
return vmh.ExecuteOnDestContextCallBack(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
return nil, nil
}

// ExecuteOnDestContext -
func (vmh *VMHostMock) ExecuteOnDestContext(gasLimit uint64, scAddress, callerAddress, calleeAddress []byte, value *big.Int, input []byte, readOnly bool) (vmOutput *vm.VMOutput, err error) {
if vmh.ExecuteOnDestContextCalled != nil {
return vmh.ExecuteOnDestContextCalled(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
if vmh.ExecuteOnDestContextCallBack != nil {
return vmh.ExecuteOnDestContextCallBack(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
return nil, nil
}

// ExecuteOnDestContext -
func (vmh *VMHostMock) ExecuteOnDestContext(gasLimit uint64, scAddress, callerAddress, calleeAddress []byte, value *big.Int, input []byte, readOnly bool) (vmOutput *vm.VMOutput, err error) {
if vmh.ExecuteOnDestContextCalled != nil {
return vmh.ExecuteOnDestContextCalled(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
if vmh.ExecuteOnDestContextCallBack != nil {
return vmh.ExecuteOnDestContextCallBack(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
return nil, nil
}

// ExecuteOnDestContext -
func (vmh *VMHostMock) ExecuteOnDestContext(gasLimit uint64, scAddress, callerAddress, calleeAddress []byte, value *big.Int, input []byte, readOnly bool) (vmOutput *vm.VMOutput, err error) {
if vmh.ExecuteOnDestContextCalled != nil {
return vmh.ExecuteOnDestContextCalled(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
if vmh.ExecuteOnDestContextCallBack != nil {
return vmh.ExecuteOnDestContextCallBack(gasLimit, scAddress, callerAddress, calleeAddress, value, input, readOnly)
}
return nil, nil
}

// InitState mocked method
func (host *VMHostMock) InitState() {
}
Expand Down
6 changes: 6 additions & 0 deletions mock/context/vmHostStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mock
import (
"github.com/multiversx/mx-chain-core-go/data/vm"
vmcommon "github.com/multiversx/mx-chain-vm-common-go"
"github.com/multiversx/mx-chain-core-go/marshal"
"github.com/multiversx/mx-chain-vm-go/config"
"github.com/multiversx/mx-chain-vm-go/crypto"
"github.com/multiversx/mx-chain-vm-go/vmhost"
Expand Down Expand Up @@ -97,6 +98,11 @@ func (vhs *VMHostStub) Crypto() crypto.VMCrypto {
return nil
}

// Marshalizer mocked method
func (vhs *VMHostStub) Marshalizer() marshal.Marshalizer {
return nil
}

// Blockchain mocked method
func (vhs *VMHostStub) Blockchain() vmhost.BlockchainContext {
if vhs.BlockchainCalled != nil {
Expand Down
38 changes: 38 additions & 0 deletions mock/contracts/A.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package contracts

import (
"math/big"

contextmock "github.com/multiversx/mx-chain-vm-go/mock/context"

Check failure on line 6 in mock/contracts/A.go

View workflow job for this annotation

GitHub Actions / golangci linter

could not import github.com/multiversx/mx-chain-vm-go/mock/context (-: # github.com/multiversx/mx-chain-vm-go/mock/context
"github.com/multiversx/mx-chain-vm-go/vmhost"
)

type A struct {
Host vmhost.VMHost
}

func (a *A) CallB() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(a.Host)
host := instance.Host
bAddress := host.Runtime().Arguments()[0]
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("A.callB called by"), host.Runtime().GetCaller()})
err := host.Async().RegisterAsyncCall("", &vmhost.AsyncCall{
Destination: bAddress,
Data: []byte("callC@sc:C"),
ValueBytes: big.NewInt(0).Bytes(),
GasLimit: 50000000,
SuccessCallback: "aCallback",
})
if err != nil {
host.Runtime().FailExecution(err)
}
return instance
}

func (a *A) ACallback() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(a.Host)
host := instance.Host
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("A.aCallback called by"), host.Runtime().GetCaller()})
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("A.aCallback called with data"), host.Runtime().Arguments()[0]})
return instance
}
37 changes: 37 additions & 0 deletions mock/contracts/B.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package contracts

import (
"math/big"

contextmock "github.com/multiversx/mx-chain-vm-go/mock/context"
"github.com/multiversx/mx-chain-vm-go/vmhost"
)

type B struct {
Host vmhost.VMHost
}

func (b *B) CallC() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(b.Host)
host := instance.Host
cAddress := host.Runtime().Arguments()[0]
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("event:B_callC")})
err := host.Async().RegisterAsyncCall("", &vmhost.AsyncCall{
Destination: cAddress,
Data: []byte("doSomething"),
ValueBytes: big.NewInt(0).Bytes(),
GasLimit: 50000000,
SuccessCallback: "bCallback",
})
if err != nil {
host.Runtime().FailExecution(err)
}
return instance
}

func (b *B) BCallback() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(b.Host)
host := instance.Host
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("event:B_callback")})
return instance
}
37 changes: 37 additions & 0 deletions mock/contracts/C.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package contracts

import (
"math/big"

contextmock "github.com/multiversx/mx-chain-vm-go/mock/context"
"github.com/multiversx/mx-chain-vm-go/vmhost"
)

type C struct {
Host vmhost.VMHost
}

func (c *C) DoSomething() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(c.Host)
host := instance.Host
dAddress := host.Runtime().Arguments()[0]
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("event:C_doSomething")})
err := host.Async().RegisterAsyncCall("", &vmhost.AsyncCall{
Destination: dAddress,
Data: []byte("doSomething"),
ValueBytes: big.NewInt(0).Bytes(),
GasLimit: 50000000,
SuccessCallback: "cCallback",
})
if err != nil {
host.Runtime().FailExecution(err)
}
return instance
}

func (c *C) CCallback() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(c.Host)
host := instance.Host
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("event:C_callback")})
return instance
}
17 changes: 17 additions & 0 deletions mock/contracts/D.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package contracts

import (
contextmock "github.com/multiversx/mx-chain-vm-go/mock/context"
"github.com/multiversx/mx-chain-vm-go/vmhost"
)

type D struct {
Host vmhost.VMHost
}

func (d *D) DoSomething() *contextmock.InstanceMock {
instance := contextmock.GetMockInstance(d.Host)
host := instance.Host
host.Output().WriteLog(host.Runtime().GetContextAddress(), nil, [][]byte{[]byte("event:D_doSomething")})
return instance
}
52 changes: 52 additions & 0 deletions test/async/scenarios/multi-level-async/multi-level-async.scen.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "multi-level async call",
"steps": [
{
"step": "setState",
"accounts": {
"address:user": {
"nonce": "0",
"balance": "1,000,000"
},
"sc:A": {
"nonce": "0",
"balance": "0",
"code": "file:../mock/contracts/A.wasm"
},
"sc:B": {
"nonce": "0",
"balance": "0",
"code": "file:../mock/contracts/B.wasm"
},
"sc:C": {
"nonce": "0",
"balance": "0",
"code": "file:../mock/contracts/C.wasm"
}
}
},
{
"step": "scCall",
"tx": {
"from": "address:user",
"to": "sc:A",
"function": "callB",
"arguments": [
"sc:B"
],
"gasLimit": "100,000,000",
"gasPrice": "0"
},
"expect": {
"status": "0",
"logs": [
"event:A_callB",
"event:B_callC",
"event:C_doSomething",
"event:B_callback",
"event:A_callback"
]
}
}
]
}
77 changes: 42 additions & 35 deletions vmhost/asyncCall.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,38 @@ type AsyncCall struct {
GasLimit uint64
GasLocked uint64

ValueBytes []byte
SuccessCallback string
ErrorCallback string
ValueBytes []byte
SuccessCallback string
ErrorCallback string
GasLimitsForCallback []uint64

CallbackClosure []byte

IsBuiltinFunctionCall bool

Results *FinishedAsyncCall
}

// Clone creates a deep clone of the AsyncCall
func (ac *AsyncCall) Clone() *AsyncCall {
clone := &AsyncCall{
CallID: ac.CallID,
Status: ac.Status,
ExecutionMode: ac.ExecutionMode,
Destination: make([]byte, len(ac.Destination)),
Data: make([]byte, len(ac.Data)),
GasLimit: ac.GasLimit,
GasLocked: ac.GasLocked,
ValueBytes: make([]byte, len(ac.ValueBytes)),
SuccessCallback: ac.SuccessCallback,
ErrorCallback: ac.ErrorCallback,
CallID: ac.CallID,
Status: ac.Status,
ExecutionMode: ac.ExecutionMode,
Destination: make([]byte, len(ac.Destination)),
Data: make([]byte, len(ac.Data)),
GasLimit: ac.GasLimit,
GasLocked: ac.GasLocked,
ValueBytes: make([]byte, len(ac.ValueBytes)),
SuccessCallback: ac.SuccessCallback,
ErrorCallback: ac.ErrorCallback,
GasLimitsForCallback: make([]uint64, len(ac.GasLimitsForCallback)),
}

copy(clone.Destination, ac.Destination)
copy(clone.Data, ac.Data)
copy(clone.ValueBytes, ac.ValueBytes)
copy(clone.GasLimitsForCallback, ac.GasLimitsForCallback)

return clone
}
Expand Down Expand Up @@ -135,17 +140,18 @@ func (ac *AsyncCall) IsInterfaceNil() bool {

func (ac *AsyncCall) toSerializable() *SerializableAsyncCall {
return &SerializableAsyncCall{
CallID: ac.CallID,
Status: SerializableAsyncCallStatus(ac.Status),
ExecutionMode: SerializableAsyncCallExecutionMode(ac.ExecutionMode),
Destination: ac.Destination,
Data: ac.Data,
GasLimit: ac.GasLimit,
GasLocked: ac.GasLocked,
ValueBytes: ac.ValueBytes,
SuccessCallback: ac.SuccessCallback,
ErrorCallback: ac.ErrorCallback,
CallbackClosure: ac.CallbackClosure,
CallID: ac.CallID,
Status: SerializableAsyncCallStatus(ac.Status),
ExecutionMode: SerializableAsyncCallExecutionMode(ac.ExecutionMode),
Destination: ac.Destination,
Data: ac.Data,
GasLimit: ac.GasLimit,
GasLocked: ac.GasLocked,
ValueBytes: ac.ValueBytes,
SuccessCallback: ac.SuccessCallback,
ErrorCallback: ac.ErrorCallback,
CallbackClosure: ac.CallbackClosure,
GasLimitsForCallback: ac.GasLimitsForCallback,
}
}

Expand All @@ -159,16 +165,17 @@ func fromSerializableAsyncCalls(serializableAsyncCalls []*SerializableAsyncCall)

func (serAsyncCall *SerializableAsyncCall) fromSerializable() *AsyncCall {
return &AsyncCall{
CallID: serAsyncCall.CallID,
Status: AsyncCallStatus(serAsyncCall.Status),
ExecutionMode: AsyncCallExecutionMode(serAsyncCall.ExecutionMode),
Destination: serAsyncCall.Destination,
Data: serAsyncCall.Data,
GasLimit: serAsyncCall.GasLimit,
GasLocked: serAsyncCall.GasLocked,
ValueBytes: serAsyncCall.ValueBytes,
SuccessCallback: serAsyncCall.SuccessCallback,
ErrorCallback: serAsyncCall.ErrorCallback,
CallbackClosure: serAsyncCall.CallbackClosure,
CallID: serAsyncCall.CallID,
Status: AsyncCallStatus(serAsyncCall.Status),
ExecutionMode: AsyncCallExecutionMode(serAsyncCall.ExecutionMode),
Destination: serAsyncCall.Destination,
Data: serAsyncCall.Data,
GasLimit: serAsyncCall.GasLimit,
GasLocked: serAsyncCall.GasLocked,
ValueBytes: serAsyncCall.ValueBytes,
SuccessCallback: serAsyncCall.SuccessCallback,
ErrorCallback: serAsyncCall.ErrorCallback,
CallbackClosure: serAsyncCall.CallbackClosure,
GasLimitsForCallback: serAsyncCall.GasLimitsForCallback,
}
}
Loading
Loading