diff --git a/arwen/host/asyncCall.go b/arwen/host/asyncCall.go index 6f7ac2484..35abf61a7 100644 --- a/arwen/host/asyncCall.go +++ b/arwen/host/asyncCall.go @@ -293,6 +293,12 @@ func (host *vmHost) processCallbackVMOutput(callbackVMOutput *vmcommon.VMOutput, output := host.Output() runtime.GetVMInput().GasProvided = 0 + + if callbackVMOutput == nil { + callbackVMOutput = output.CreateVMOutputInCaseOfError(callBackErr) + } + + output.SetReturnMessage(callbackVMOutput.ReturnMessage) output.Finish([]byte(callbackVMOutput.ReturnCode.String())) output.Finish([]byte(runtime.GetCurrentTxHash())) diff --git a/arwen/host/execution_test.go b/arwen/host/execution_test.go index d0e464c8b..ae57165dd 100644 --- a/arwen/host/execution_test.go +++ b/arwen/host/execution_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/ElrondNetwork/arwen-wasm-vm/arwen" + "github.com/ElrondNetwork/arwen-wasm-vm/config" "github.com/ElrondNetwork/arwen-wasm-vm/mock" vmcommon "github.com/ElrondNetwork/elrond-vm-common" "github.com/stretchr/testify/assert" @@ -1091,6 +1092,31 @@ func TestExecution_AsyncCall_BuiltinFails(t *testing.T) { require.Equal(t, [][]byte{[]byte("hello"), {4}}, vmOutput.ReturnData) } +func TestExecution_AsyncCall_CallBackFailsBeforeExecution(t *testing.T) { + config.AsyncCallbackGasLockForTests = uint64(2) + + code := GetTestSCCode("async-call-builtin", "../../") + scBalance := big.NewInt(1000) + + host, stubBlockchainHook := DefaultTestArwenForCall(t, code, scBalance) + stubBlockchainHook.ProcessBuiltInFunctionCalled = dummyProcessBuiltInFunction + host.protocolBuiltinFunctions = getDummyBuiltinFunctionNames() + + input := DefaultTestContractCallInput() + input.RecipientAddr = parentAddress + input.Function = "performAsyncCallToBuiltin" + input.Arguments = [][]byte{{1}} + input.GasProvided = 1000000 + input.CurrentTxHash = []byte("txhash") + + vmOutput, err := host.RunSmartContractCall(input) + require.Nil(t, err) + + require.NotNil(t, vmOutput) + require.Equal(t, vmcommon.Ok, vmOutput.ReturnCode) + require.Equal(t, [][]byte{[]byte("hello"), []byte("out of gas"), []byte("txhash")}, vmOutput.ReturnData) +} + func TestExecution_CreateNewContract_Success(t *testing.T) { parentCode := GetTestSCCode("deployer", "../../") childCode := GetTestSCCode("init-correct", "../../") diff --git a/arwen/host/execution_vmoutputs_test.go b/arwen/host/execution_vmoutputs_test.go index ea6d295dd..dfb880456 100644 --- a/arwen/host/execution_vmoutputs_test.go +++ b/arwen/host/execution_vmoutputs_test.go @@ -881,6 +881,8 @@ func expectedVMOutput_AsyncCall_CallBackFails(parentCode []byte, childCode []byt AddFinishData(vmOutput, []byte("user error")) AddFinishData(vmOutput, []byte("txhash")) + vmOutput.ReturnMessage = "callBack error" + return vmOutput } diff --git a/arwen/host/testInitializer.go b/arwen/host/testInitializer.go index aebfacffe..45d2aeb66 100644 --- a/arwen/host/testInitializer.go +++ b/arwen/host/testInitializer.go @@ -25,6 +25,8 @@ var userAddress = []byte("userAccount.....................") var parentAddress = []byte("parentSC........................") var childAddress = []byte("childSC.........................") +var CustomGasSchedule = config.GasScheduleMap(nil) + // GetSCCode retrieves the bytecode of a WASM module from a file func GetSCCode(fileName string) []byte { code, err := ioutil.ReadFile(filepath.Clean(fileName)) @@ -101,10 +103,15 @@ func DefaultTestArwenForTwoSCs(t *testing.T, parentCode []byte, childCode []byte } func DefaultTestArwen(tb testing.TB, blockchain vmcommon.BlockchainHook, crypto vmcommon.CryptoHook) (*vmHost, error) { + gasSchedule := CustomGasSchedule + if gasSchedule == nil { + gasSchedule = config.MakeGasMapForTests() + } + host, err := NewArwenVM(blockchain, crypto, &arwen.VMHostParameters{ VMType: defaultVMType, BlockGasLimit: uint64(1000), - GasSchedule: config.MakeGasMapForTests(), + GasSchedule: gasSchedule, ProtocolBuiltinFunctions: make(vmcommon.FunctionNames), ElrondProtectedKeyPrefix: []byte("ELROND"), }) diff --git a/config/gasSchedule.go b/config/gasSchedule.go index 9e1417d56..370d3a5b2 100644 --- a/config/gasSchedule.go +++ b/config/gasSchedule.go @@ -8,7 +8,8 @@ import ( ) const GasValueForTests = 1 -const AsyncCallbackGasLockForTests = 100_000 + +var AsyncCallbackGasLockForTests = uint64(100_000) // GasScheduleMap (alias) is the map for gas schedule type GasScheduleMap = map[string]map[string]uint64