diff --git a/executor/vmHooks.go b/executor/vmHooks.go index 978d6fae3..87b9b1e3c 100644 --- a/executor/vmHooks.go +++ b/executor/vmHooks.go @@ -113,6 +113,7 @@ type ManagedVMHooks interface { ManagedGetPrevBlockRandomSeed(resultHandle int32) ManagedGetReturnData(resultID int32, resultHandle int32) ManagedGetMultiESDTCallValue(multiCallValueHandle int32) + ManagedGetBackTransfers(esdtTransfersValueHandle int32, callValueHandle int32) ManagedGetESDTBalance(addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32) ManagedGetESDTTokenData(addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32, propertiesHandle int32, hashHandle int32, nameHandle int32, attributesHandle int32, creatorHandle int32, royaltiesHandle int32, urisHandle int32) ManagedAsyncCall(destHandle int32, valueHandle int32, functionHandle int32, argumentsHandle int32) diff --git a/executor/wrapper/wrapperVMHooks.go b/executor/wrapper/wrapperVMHooks.go index 9f8fcece9..ee827f4c7 100644 --- a/executor/wrapper/wrapperVMHooks.go +++ b/executor/wrapper/wrapperVMHooks.go @@ -805,6 +805,14 @@ func (w *WrapperVMHooks) ManagedGetMultiESDTCallValue(multiCallValueHandle int32 w.logger.LogVMHookCallAfter(callInfo) } +// ManagedGetBackTransfers VM hook wrapper +func (w *WrapperVMHooks) ManagedGetBackTransfers(esdtTransfersValueHandle int32, callValueHandle int32) { + callInfo := fmt.Sprintf("ManagedGetBackTransfers(%d, %d)", esdtTransfersValueHandle, callValueHandle) + w.logger.LogVMHookCallBefore(callInfo) + w.wrappedVMHooks.ManagedGetBackTransfers(esdtTransfersValueHandle, callValueHandle) + w.logger.LogVMHookCallAfter(callInfo) +} + // ManagedGetESDTBalance VM hook wrapper func (w *WrapperVMHooks) ManagedGetESDTBalance(addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32) { callInfo := fmt.Sprintf("ManagedGetESDTBalance(%d, %d, %d, %d)", addressHandle, tokenIDHandle, nonce, valueHandle) diff --git a/go.mod b/go.mod index b2e3cf4af..352e698d8 100644 --- a/go.mod +++ b/go.mod @@ -8,11 +8,11 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/gogo/protobuf v1.3.2 github.com/mitchellh/mapstructure v1.5.0 - github.com/multiversx/mx-chain-core-go v1.2.15-0.20230828081708-1d1190bec635 + github.com/multiversx/mx-chain-core-go v1.2.17-0.20230918144211-8728c8a6e2d5 github.com/multiversx/mx-chain-crypto-go v1.2.8 github.com/multiversx/mx-chain-logger-go v1.0.13 github.com/multiversx/mx-chain-scenario-go v1.2.1 - github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230901130135-4d211b1a41d2 + github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230918144414-73020ec780b7 github.com/multiversx/mx-components-big-int v1.0.0 github.com/pelletier/go-toml v1.9.3 github.com/stretchr/testify v1.8.1 diff --git a/go.sum b/go.sum index 71a1cf546..91848776f 100644 --- a/go.sum +++ b/go.sum @@ -81,16 +81,16 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiversx/mx-chain-core-go v1.2.15-0.20230828081708-1d1190bec635 h1:BtuOBkYy3heZYLaqRys94rPwEiQq/HKHYRL8RXAq46A= -github.com/multiversx/mx-chain-core-go v1.2.15-0.20230828081708-1d1190bec635/go.mod h1:BILOGHUOIG5dNNX8cgkzCNfDaVtoYrJRYcPnpxRMH84= +github.com/multiversx/mx-chain-core-go v1.2.17-0.20230918144211-8728c8a6e2d5 h1:j20zxnqhffqW35Cek5yvRYYANE+ws4XMB2G4t4o4aOs= +github.com/multiversx/mx-chain-core-go v1.2.17-0.20230918144211-8728c8a6e2d5/go.mod h1:BILOGHUOIG5dNNX8cgkzCNfDaVtoYrJRYcPnpxRMH84= github.com/multiversx/mx-chain-crypto-go v1.2.8 h1:wOgVlUaO5X4L8iEbFjcQcL8SZvv6WZ7LqH73BiRPhxU= github.com/multiversx/mx-chain-crypto-go v1.2.8/go.mod h1:fkaWKp1rbQN9wPKya5jeoRyC+c/SyN/NfggreyeBw+8= github.com/multiversx/mx-chain-logger-go v1.0.13 h1:eru/TETo0MkO4ZTnXsQDKf4PBRpAXmqjT02klNT/JnY= github.com/multiversx/mx-chain-logger-go v1.0.13/go.mod h1:MZJhTAtZTJxT+yK2EHc4ZW3YOHUc1UdjCD0iahRNBZk= github.com/multiversx/mx-chain-scenario-go v1.2.1 h1:9eC6VcOEAKRRKZ7EbSWPLzCdNIMWwuNBtAZlgR4cSMA= github.com/multiversx/mx-chain-scenario-go v1.2.1/go.mod h1:EuZY7DpNFHVNSxJR8dKE1z2I8gBYfEFFPSwNUOXptqE= -github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230901130135-4d211b1a41d2 h1:5ZyyNUvyV4QLIjz/tHgqSDC99FmF3H2q2p3NajOTkVc= -github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230901130135-4d211b1a41d2/go.mod h1:uDaefuPXa9p0sb+wrUk16J0z+U324Hh894Y5oVXeVdI= +github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230918144414-73020ec780b7 h1:MBABPvX640D6NkmuIaEhM8v/WLdSDRRIfEjilQX2NO0= +github.com/multiversx/mx-chain-vm-common-go v1.5.6-0.20230918144414-73020ec780b7/go.mod h1:VtmaxMU7FtRdTLLcLd0D01vcTm0drVYvaJ0U88ikr38= github.com/multiversx/mx-components-big-int v1.0.0 h1:Wkr8lSzK2nDqixOrrBa47VNuqdhV1m/aJhaP1EMaiS8= github.com/multiversx/mx-components-big-int v1.0.0/go.mod h1:maIEMgHlNE2u78JaDD0oLzri+ShgU4okHfzP3LWGdQM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/integrationTests/json/scenariosAdderLog_test.go b/integrationTests/json/scenariosAdderLog_test.go index fbbb832e3..0a124f728 100644 --- a/integrationTests/json/scenariosAdderLog_test.go +++ b/integrationTests/json/scenariosAdderLog_test.go @@ -52,7 +52,7 @@ GetPointsUsed: 135352 GetPointsUsed: 135352 Reset: true SetPointsUsed: 0 -SetGasLimit: 18446744073708343115 +SetGasLimit: 9223372036853567307 SetBreakpointValue: 0 HasFunction(getSum): true CallFunction(getSum): diff --git a/integrationTests/json/scenariosContracts_test.go b/integrationTests/json/scenariosContracts_test.go index 606abc605..1df613815 100644 --- a/integrationTests/json/scenariosContracts_test.go +++ b/integrationTests/json/scenariosContracts_test.go @@ -2,6 +2,8 @@ package vmjsonintegrationtest import ( "testing" + + worldhook "github.com/multiversx/mx-chain-vm-go/mock/world" ) func TestRustAdder(t *testing.T) { @@ -69,6 +71,7 @@ func TestDnsContract(t *testing.T) { ScenariosTest(t). Folder("dns"). + WithEnableEpochsHandler(worldhook.EnableEpochsHandlerStubNoFlags()). Run(). CheckNoError() } diff --git a/integrationTests/json/scenariosExecutorLogs_test.go b/integrationTests/json/scenariosExecutorLogs_test.go index 00c1a22e4..24230e0f2 100644 --- a/integrationTests/json/scenariosExecutorLogs_test.go +++ b/integrationTests/json/scenariosExecutorLogs_test.go @@ -3,6 +3,7 @@ package vmjsonintegrationtest import ( "testing" + worldhook "github.com/multiversx/mx-chain-vm-go/mock/world" "github.com/multiversx/mx-chain-vm-go/testcommon/testexecutor" "github.com/multiversx/mx-chain-vm-go/wasmer" "github.com/multiversx/mx-chain-vm-go/wasmer2" @@ -223,6 +224,7 @@ func TestDnsContractLog(t *testing.T) { expected := ScenariosTest(t). Folder("dns"). + WithEnableEpochsHandler(worldhook.EnableEpochsHandlerStubNoFlags()). WithExecutorFactory(wasmer.ExecutorFactory()). WithExecutorLogs(). Run(). @@ -231,6 +233,7 @@ func TestDnsContractLog(t *testing.T) { ScenariosTest(t). Folder("dns"). + WithEnableEpochsHandler(worldhook.EnableEpochsHandlerStubNoFlags()). WithExecutorFactory(wasmer2.ExecutorFactory()). WithExecutorLogs(). Run(). diff --git a/integrationTests/json/scenariosTestCommon.go b/integrationTests/json/scenariosTestCommon.go index 521d416da..699c4d955 100644 --- a/integrationTests/json/scenariosTestCommon.go +++ b/integrationTests/json/scenariosTestCommon.go @@ -11,8 +11,10 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" logger "github.com/multiversx/mx-chain-logger-go" mc "github.com/multiversx/mx-chain-scenario-go/controller" + vmi "github.com/multiversx/mx-chain-vm-common-go" "github.com/multiversx/mx-chain-vm-go/executor" executorwrapper "github.com/multiversx/mx-chain-vm-go/executor/wrapper" + worldhook "github.com/multiversx/mx-chain-vm-go/mock/world" am "github.com/multiversx/mx-chain-vm-go/scenarioexec" "github.com/multiversx/mx-chain-vm-go/testcommon/testexecutor" "github.com/stretchr/testify/require" @@ -33,23 +35,25 @@ func getTestRoot() string { // ScenariosTestBuilder defines the Scenarios builder component type ScenariosTestBuilder struct { - t *testing.T - folder string - singleFile string - exclusions []string - executorLogger executorwrapper.ExecutorLogger - executorFactory executor.ExecutorAbstractFactory - currentError error + t *testing.T + folder string + singleFile string + exclusions []string + executorLogger executorwrapper.ExecutorLogger + executorFactory executor.ExecutorAbstractFactory + enableEpochsHandler vmi.EnableEpochsHandler + currentError error } // ScenariosTest will create a new ScenariosTestBuilder instance func ScenariosTest(t *testing.T) *ScenariosTestBuilder { return &ScenariosTestBuilder{ - t: t, - folder: "", - singleFile: "", - executorLogger: nil, - executorFactory: nil, + t: t, + folder: "", + singleFile: "", + executorLogger: nil, + executorFactory: nil, + enableEpochsHandler: worldhook.EnableEpochsHandlerStubAllFlags(), } } @@ -89,6 +93,12 @@ func (mtb *ScenariosTestBuilder) WithExecutorFactory(executorFactory executor.Ex return mtb } +// WithEnableEpochsHandler overrides the epoch flags +func (mtb *ScenariosTestBuilder) WithEnableEpochsHandler(enableEpochsHandler vmi.EnableEpochsHandler) *ScenariosTestBuilder { + mtb.enableEpochsHandler = enableEpochsHandler + return mtb +} + // Run will start the testing process func (mtb *ScenariosTestBuilder) Run() *ScenariosTestBuilder { executor, err := am.NewVMTestExecutor() @@ -98,7 +108,7 @@ func (mtb *ScenariosTestBuilder) Run() *ScenariosTestBuilder { if check.IfNil(mtb.executorFactory) { mtb.executorFactory = testexecutor.NewDefaultTestExecutorFactory(mtb.t) } - + executor.World.EnableEpochsHandler = mtb.enableEpochsHandler executor.OverrideVMExecutor = mtb.executorFactory if mtb.executorLogger != nil { executor.OverrideVMExecutor = executorwrapper.NewWrappedExecutorFactory( diff --git a/mock/context/executorMockFunc.go b/mock/context/executorMockFunc.go index b468e8af1..c4cc3f95c 100644 --- a/mock/context/executorMockFunc.go +++ b/mock/context/executorMockFunc.go @@ -100,6 +100,7 @@ var functionNames = map[string]struct{}{ "managedGetPrevBlockRandomSeed": empty, "managedGetReturnData": empty, "managedGetMultiESDTCallValue": empty, + "managedGetBackTransfers": empty, "managedGetESDTBalance": empty, "managedGetESDTTokenData": empty, "managedAsyncCall": empty, diff --git a/mock/context/outputContextMock.go b/mock/context/outputContextMock.go index 309249cb5..3a8ffcb34 100644 --- a/mock/context/outputContextMock.go +++ b/mock/context/outputContextMock.go @@ -166,6 +166,10 @@ func (o *OutputContextMock) DeleteFirstReturnData() { // WriteLog mocked method func (o *OutputContextMock) WriteLog(_ []byte, _ [][]byte, _ [][]byte) {} +// WriteLogWithIdentifier mocked method +func (o *OutputContextMock) WriteLogWithIdentifier(_ []byte, _ [][]byte, _ [][]byte, _ []byte) { +} + // TransferValueOnly mocked method func (o *OutputContextMock) TransferValueOnly(_ []byte, _ []byte, _ *big.Int, _ bool) error { return o.TransferResult @@ -177,7 +181,7 @@ func (o *OutputContextMock) Transfer(_ []byte, _ []byte, _ uint64, _ uint64, _ * } // TransferESDT mocked method -func (o *OutputContextMock) TransferESDT(transfersArgs *vmhost.ESDTTransfersArgs, _ *vmcommon.ContractCallInput) (uint64, error) { +func (o *OutputContextMock) TransferESDT(_ *vmhost.ESDTTransfersArgs, _ *vmcommon.ContractCallInput) (uint64, error) { return 0, nil } diff --git a/mock/context/outputContextStub.go b/mock/context/outputContextStub.go index 64b1bf8d0..69f416526 100644 --- a/mock/context/outputContextStub.go +++ b/mock/context/outputContextStub.go @@ -24,6 +24,7 @@ type OutputContextStub struct { GetOutputAccountCalled func(address []byte) (*vmcommon.OutputAccount, bool) DeleteOutputAccountCalled func(address []byte) WriteLogCalled func(address []byte, topics [][]byte, data [][]byte) + WriteLogWithIdentifierCalled func(address []byte, topics [][]byte, data [][]byte, identifier []byte) TransferCalled func(destination []byte, sender []byte, gasLimit uint64, gasLocked uint64, value *big.Int, asyncData []byte, input []byte) error TransferESDTCalled func(transfersArgs *vmhost.ESDTTransfersArgs, input *vmcommon.ContractCallInput) (uint64, error) GetRefundCalled func() uint64 @@ -144,6 +145,13 @@ func (o *OutputContextStub) WriteLog(address []byte, topics [][]byte, data [][]b } } +// WriteLogWithIdentifier mocked method +func (o *OutputContextStub) WriteLogWithIdentifier(address []byte, topics [][]byte, data [][]byte, identifier []byte) { + if o.WriteLogWithIdentifierCalled != nil { + o.WriteLogWithIdentifierCalled(address, topics, data, identifier) + } +} + // TransferValueOnly mocked method func (o *OutputContextStub) TransferValueOnly(destination []byte, sender []byte, value *big.Int, checkPayable bool) error { if o.TransferValueOnlyCalled != nil { diff --git a/mock/contracts/backTransferSC.go b/mock/contracts/backTransferSC.go new file mode 100644 index 000000000..aad939176 --- /dev/null +++ b/mock/contracts/backTransferSC.go @@ -0,0 +1,134 @@ +package contracts + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/multiversx/mx-chain-core-go/data/vm" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/txDataBuilder" + mock "github.com/multiversx/mx-chain-vm-go/mock/context" + test "github.com/multiversx/mx-chain-vm-go/testcommon" + "github.com/multiversx/mx-chain-vm-go/vmhost" + "github.com/multiversx/mx-chain-vm-go/vmhost/vmhooks" +) + +// BackTransfer_ParentCallsChild is an exposed mock contract method +func BackTransfer_ParentCallsChild(instanceMock *mock.InstanceMock, config interface{}) { + instanceMock.AddMockMethod("callChild", func() *mock.InstanceMock { + host := instanceMock.Host + instance := mock.GetMockInstance(host) + + storedResult := []byte("ok") + + testConfig := config.(*test.TestConfig) + input := test.DefaultTestContractCallInput() + input.GasProvided = testConfig.GasProvidedToChild + input.CallerAddr = testConfig.ParentAddress + input.RecipientAddr = testConfig.ChildAddress + input.Function = "childFunction" + returnValue := ExecuteOnDestContextInMockContracts(host, input) + if returnValue != 0 { + host.Runtime().FailExecution(fmt.Errorf("return value %d", returnValue)) + } + managedTypes := host.ManagedTypes() + + arguments := host.Runtime().Arguments() + if len(arguments) > 0 { + checkBackTransfers := arguments[0] + if checkBackTransfers[0] == 1 { + esdtTransfers, egld := managedTypes.GetBackTransfers() + if len(esdtTransfers) != 1 { + host.Runtime().FailExecution(fmt.Errorf("found esdt transfers %d", len(esdtTransfers))) + storedResult = []byte("err") + } + if !bytes.Equal(test.ESDTTestTokenName, esdtTransfers[0].ESDTTokenName) { + host.Runtime().FailExecution(fmt.Errorf("invalid token name %s", string(esdtTransfers[0].ESDTTokenName))) + storedResult = []byte("err") + } + if big.NewInt(0).SetUint64(testConfig.ESDTTokensToTransfer).Cmp(esdtTransfers[0].ESDTValue) != 0 { + host.Runtime().FailExecution(fmt.Errorf("invalid token value %d", esdtTransfers[0].ESDTValue.Uint64())) + storedResult = []byte("err") + } + if egld.Cmp(big.NewInt(testConfig.TransferFromChildToParent)) != 0 { + host.Runtime().FailExecution(fmt.Errorf("invalid egld value %d", egld)) + storedResult = []byte("err") + } + } + } + + _, err := host.Storage().SetStorage(test.ParentKeyA, storedResult) + if err != nil { + host.Runtime().FailExecution(err) + } + + return instance + }) +} + +// BackTransfer_ChildMakesAsync is an exposed mock contract method +func BackTransfer_ChildMakesAsync(instanceMock *mock.InstanceMock, config interface{}) { + instanceMock.AddMockMethod("childFunction", func() *mock.InstanceMock { + host := instanceMock.Host + instance := mock.GetMockInstance(host) + testConfig := config.(*test.TestConfig) + + callData := txDataBuilder.NewBuilder() + callData.Func("wasteGas") + callData.Int64(0) + + err := host.Async().RegisterAsyncCall("testGroup", &vmhost.AsyncCall{ + Status: vmhost.AsyncCallPending, + Destination: testConfig.NephewAddress, + Data: callData.ToBytes(), + ValueBytes: big.NewInt(0).Bytes(), + SuccessCallback: testConfig.SuccessCallback, + ErrorCallback: testConfig.ErrorCallback, + GasLimit: uint64(300), + GasLocked: testConfig.GasToLock, + CallbackClosure: nil, + }) + if err != nil { + host.Runtime().FailExecution(err) + } + return instance + }) +} + +// BackTransfer_ChildCallback is an exposed mock contract method +func BackTransfer_ChildCallback(instanceMock *mock.InstanceMock, config interface{}) { + instanceMock.AddMockMethod("myCallback", func() *mock.InstanceMock { + host := instanceMock.Host + instance := mock.GetMockInstance(host) + testConfig := config.(*test.TestConfig) + + valueBytes := big.NewInt(testConfig.TransferFromChildToParent).Bytes() + err := host.Output().Transfer( + testConfig.ParentAddress, + testConfig.ChildAddress, 0, 0, big.NewInt(0).SetBytes(valueBytes), nil, []byte{}, vm.DirectCall) + if err != nil { + host.Runtime().FailExecution(err) + } + + transfer := &vmcommon.ESDTTransfer{ + ESDTValue: big.NewInt(int64(testConfig.ESDTTokensToTransfer)), + ESDTTokenName: test.ESDTTestTokenName, + ESDTTokenType: 0, + ESDTTokenNonce: 0, + } + + ret := vmhooks.TransferESDTNFTExecuteWithTypedArgs( + host, + testConfig.ParentAddress, + []*vmcommon.ESDTTransfer{transfer}, + int64(testConfig.GasProvidedToChild), + nil, + nil) + if ret != 0 { + host.Runtime().FailExecution(fmt.Errorf("Transfer ESDT failed")) + } + + return instance + }) +} diff --git a/mock/world/builtinFunctionsWrapper.go b/mock/world/builtinFunctionsWrapper.go index d19592e2b..836c639fc 100644 --- a/mock/world/builtinFunctionsWrapper.go +++ b/mock/world/builtinFunctionsWrapper.go @@ -3,12 +3,10 @@ package worldmock import ( "bytes" - "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/marshal" vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" - "github.com/multiversx/mx-chain-vm-common-go/mock" "github.com/multiversx/mx-chain-vm-go/config" ) @@ -35,30 +33,13 @@ func NewBuiltinFunctionsWrapper( dnsMap := makeDNSAddresses(numDNSAddresses) argsBuiltIn := builtInFunctions.ArgsCreateBuiltInFunctionContainer{ - GasMap: gasMap, - MapDNSAddresses: dnsMap, - MapDNSV2Addresses: dnsMap, - Marshalizer: WorldMarshalizer, - Accounts: world.AccountsAdapter, - ShardCoordinator: world, - EnableEpochsHandler: &mock.EnableEpochsHandlerStub{ - IsFlagEnabledCalled: func(flag core.EnableEpochFlag) bool { - return flag == builtInFunctions.CheckCorrectTokenIDForTransferRoleFlag || - flag == builtInFunctions.ESDTTransferRoleFlag || - flag == builtInFunctions.GlobalMintBurnFlag || - flag == builtInFunctions.TransferToMetaFlag || - flag == builtInFunctions.CheckFrozenCollectionFlag || - flag == builtInFunctions.FixAsyncCallbackCheckFlag || - flag == builtInFunctions.ESDTNFTImprovementV1Flag || - flag == builtInFunctions.SaveToSystemAccountFlag || - flag == builtInFunctions.ValueLengthCheckFlag || - flag == builtInFunctions.CheckFunctionArgumentFlag || - flag == builtInFunctions.FixOldTokenLiquidityFlag || - flag == builtInFunctions.AlwaysSaveTokenMetaDataFlag || - flag == builtInFunctions.SetGuardianFlag || - flag == builtInFunctions.ScToScLogEventFlag - }, - }, + GasMap: gasMap, + MapDNSAddresses: dnsMap, + MapDNSV2Addresses: dnsMap, + Marshalizer: WorldMarshalizer, + Accounts: world.AccountsAdapter, + ShardCoordinator: world, + EnableEpochsHandler: world.EnableEpochsHandler, GuardedAccountHandler: world.GuardedAccountHandler, MaxNumOfAddressesForTransferRole: 100, } diff --git a/mock/world/enableEpochsHandlerStub.go b/mock/world/enableEpochsHandlerStub.go index 5b36ed100..e98aa186f 100644 --- a/mock/world/enableEpochsHandlerStub.go +++ b/mock/world/enableEpochsHandlerStub.go @@ -2,6 +2,7 @@ package worldmock import ( "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" "github.com/multiversx/mx-chain-vm-go/vmhost" ) @@ -64,7 +65,26 @@ func EnableEpochsHandlerStubAllFlags() *EnableEpochsHandlerStub { flag == vmhost.FailExecutionOnEveryAPIErrorFlag || flag == vmhost.RefactorContextFlag || flag == vmhost.DisableExecByCallerFlag || - flag == vmhost.CheckExecuteOnReadOnlyFlag + flag == vmhost.CheckExecuteOnReadOnlyFlag || + flag == builtInFunctions.CheckCorrectTokenIDForTransferRoleFlag || + flag == builtInFunctions.ESDTTransferRoleFlag || + flag == builtInFunctions.GlobalMintBurnFlag || + flag == builtInFunctions.TransferToMetaFlag || + flag == builtInFunctions.CheckFrozenCollectionFlag || + flag == builtInFunctions.FixAsyncCallbackCheckFlag || + flag == builtInFunctions.ESDTNFTImprovementV1Flag || + flag == builtInFunctions.SaveToSystemAccountFlag || + flag == builtInFunctions.ValueLengthCheckFlag || + flag == builtInFunctions.CheckTransferFlag || + flag == builtInFunctions.CheckFunctionArgumentFlag || + flag == builtInFunctions.FixOldTokenLiquidityFlag || + flag == builtInFunctions.AlwaysSaveTokenMetaDataFlag || + flag == builtInFunctions.SetGuardianFlag || + flag == builtInFunctions.WipeSingleNFTLiquidityDecreaseFlag || + flag == builtInFunctions.ConsistentTokensValuesLengthCheckFlag || + flag == builtInFunctions.ChangeUsernameFlag || + flag == builtInFunctions.AutoBalanceDataTriesFlag || + flag == builtInFunctions.ScToScLogEventFlag }, } } diff --git a/mock/world/worldDef.go b/mock/world/worldDef.go index ee3eeec33..7893ef7a1 100644 --- a/mock/world/worldDef.go +++ b/mock/world/worldDef.go @@ -50,6 +50,7 @@ type MockWorld struct { IsLimitedTransferValue bool GuardedAccountHandler vmcommon.GuardedAccountHandler ProvidedBlockchainHook vmcommon.BlockchainHook + EnableEpochsHandler vmcommon.EnableEpochsHandler OtherVMOutputMap map[string]*vmcommon.VMOutput } @@ -57,16 +58,17 @@ type MockWorld struct { func NewMockWorld() *MockWorld { accountMap := NewAccountMap() world := &MockWorld{ - SelfShardID: 0, - AcctMap: accountMap, - AccountsAdapter: nil, - PreviousBlockInfo: nil, - CurrentBlockInfo: nil, - Blockhashes: nil, - NewAddressMocks: nil, - CompiledCode: make(map[string][]byte), - BuiltinFuncs: nil, - OtherVMOutputMap: make(map[string]*vmcommon.VMOutput), + SelfShardID: 0, + AcctMap: accountMap, + AccountsAdapter: nil, + PreviousBlockInfo: nil, + CurrentBlockInfo: nil, + Blockhashes: nil, + NewAddressMocks: nil, + CompiledCode: make(map[string][]byte), + BuiltinFuncs: nil, + EnableEpochsHandler: EnableEpochsHandlerStubAllFlags(), + OtherVMOutputMap: make(map[string]*vmcommon.VMOutput), } world.AccountsAdapter = NewMockAccountsAdapter(world) world.GuardedAccountHandler = NewMockGuardedAccountHandler() diff --git a/scenarioexec/exec.go b/scenarioexec/exec.go index 9cb6a28f7..cef9f4f7d 100644 --- a/scenarioexec/exec.go +++ b/scenarioexec/exec.go @@ -85,7 +85,7 @@ func (ae *VMTestExecutor) InitVM(scenGasSchedule mj.GasSchedule) error { ProtectedKeyPrefix: []byte(core.ProtectedKeyPrefix), ESDTTransferParser: esdtTransferParser, EpochNotifier: &mock.EpochNotifierStub{}, - EnableEpochsHandler: worldhook.EnableEpochsHandlerStubAllFlags(), + EnableEpochsHandler: ae.World.EnableEpochsHandler, WasmerSIGSEGVPassthrough: false, Hasher: worldhook.DefaultHasher, }) diff --git a/scenarioexec/stepCheckTxResult.go b/scenarioexec/stepCheckTxResult.go index 47e804c5f..bf6a177b3 100644 --- a/scenarioexec/stepCheckTxResult.go +++ b/scenarioexec/stepCheckTxResult.go @@ -118,14 +118,13 @@ func (ae *VMTestExecutor) checkTxLog( checkBytesListPretty(expectedLog.Topics), ae.exprReconstructor.ReconstructList(actualLog.Topics, er.NoHint)) } - //TODO fix this when integrating feat/logEvents - //if !expectedLog.Data.CheckList(actualLog.Data) { - // return fmt.Errorf("bad log data. Tx '%s'. Log index: %d. Want:\n%s\nGot:\n%s", - // txIndex, - // logIndex, - // mjwrite.LogToString(expectedLog), - // mjwrite.LogToString(ae.convertLogToTestFormat(actualLog))) - //} + if !expectedLog.Data.CheckList(actualLog.Data) { + return fmt.Errorf("bad log data. Tx '%s'. Log index: %d. Want:\n%s\nGot:\n%s", + txIndex, + logIndex, + mjwrite.LogToString(expectedLog), + mjwrite.LogToString(ae.convertLogToTestFormat(actualLog))) + } return nil } diff --git a/scenarioexec/stepRunTx.go b/scenarioexec/stepRunTx.go index 761b3b16c..f8d54155d 100644 --- a/scenarioexec/stepRunTx.go +++ b/scenarioexec/stepRunTx.go @@ -74,8 +74,8 @@ func (ae *VMTestExecutor) executeTx(txIndex string, tx *mj.Transaction) (*vmcomm // the sender is the contract itself during SC queries tx.From = tx.To // gas restrictions waived during SC queries - tx.GasLimit.Value = math.MaxUint64 - gasForExecution = math.MaxUint64 + tx.GasLimit.Value = math.MaxInt64 + gasForExecution = math.MaxInt64 fallthrough case mj.ScCall: output, err = ae.scCall(txIndex, tx, gasForExecution) diff --git a/scenarioexec/util.go b/scenarioexec/util.go index fc9a39c2a..faa8d01b3 100644 --- a/scenarioexec/util.go +++ b/scenarioexec/util.go @@ -159,8 +159,7 @@ func (ae *VMTestExecutor) convertLogToTestFormat(outputLog *vmcommon.LogEntry) * outputLog.Identifier, ae.exprReconstructor.Reconstruct(outputLog.Identifier, er.StrHint)), - //TODO fix this when integrating feat/logEvents - // Data: dataField, + Data: dataField, Topics: topics, } diff --git a/test/crowdfunding-esdt/scenarios/_generated_fund.scen.json b/test/crowdfunding-esdt/scenarios/_generated_fund.scen.json index 96eff2834..c461d43b6 100644 --- a/test/crowdfunding-esdt/scenarios/_generated_fund.scen.json +++ b/test/crowdfunding-esdt/scenarios/_generated_fund.scen.json @@ -116,7 +116,7 @@ ], "function": "fund", "arguments": [], - "gasLimit": "18446744073709551615", + "gasLimit": "9223372036854775807", "gasPrice": "0" }, "expect": { diff --git a/test/crowdfunding-esdt/scenarios/_generated_sc_err.scen.json b/test/crowdfunding-esdt/scenarios/_generated_sc_err.scen.json index 4cf8d3470..0efef9bd3 100644 --- a/test/crowdfunding-esdt/scenarios/_generated_sc_err.scen.json +++ b/test/crowdfunding-esdt/scenarios/_generated_sc_err.scen.json @@ -131,7 +131,7 @@ "egldValue": "1000", "function": "fund", "arguments": [], - "gasLimit": "18446744073709551615", + "gasLimit": "9223372036854775807", "gasPrice": "0" }, "expect": { diff --git a/test/delegation/v0_2/purchase/purchase_buy_1x.scen.json b/test/delegation/v0_2/purchase/purchase_buy_1x.scen.json index a676f8cc7..d9c5dd102 100644 --- a/test/delegation/v0_2/purchase/purchase_buy_1x.scen.json +++ b/test/delegation/v0_2/purchase/purchase_buy_1x.scen.json @@ -68,8 +68,7 @@ ], "data": [ "str:DirectCall", - "str:purchaseStake", - "str:delegator_1___________________s1" + "str:payment for stake" ] }, { diff --git a/test/delegation/v0_2/purchase/purchase_buy_2x.scen.json b/test/delegation/v0_2/purchase/purchase_buy_2x.scen.json index b67580a83..06b261227 100644 --- a/test/delegation/v0_2/purchase/purchase_buy_2x.scen.json +++ b/test/delegation/v0_2/purchase/purchase_buy_2x.scen.json @@ -68,8 +68,7 @@ ], "data": [ "str:DirectCall", - "str:purchaseStake", - "str:delegator_1___________________s1" + "str:payment for stake" ] }, { @@ -116,8 +115,7 @@ ], "data": [ "str:DirectCall", - "str:purchaseStake", - "str:delegator_1___________________s1" + "str:payment for stake" ] }, { diff --git a/test/delegation/v0_2/unstake/stake_unstake_1.scen.json b/test/delegation/v0_2/unstake/stake_unstake_1.scen.json index b5613e413..86b7bbd68 100644 --- a/test/delegation/v0_2/unstake/stake_unstake_1.scen.json +++ b/test/delegation/v0_2/unstake/stake_unstake_1.scen.json @@ -94,8 +94,7 @@ ], "data": [ "str:DirectCall", - "str:unstake", - "567,000,000,000" + "str:delegation unstake" ] }, { diff --git a/test/delegation/v0_3/test/integration/main/07_activate_pt_2.steps.json b/test/delegation/v0_3/test/integration/main/07_activate_pt_2.steps.json index c57d37e02..a83cdb4b0 100644 --- a/test/delegation/v0_3/test/integration/main/07_activate_pt_2.steps.json +++ b/test/delegation/v0_3/test/integration/main/07_activate_pt_2.steps.json @@ -46,8 +46,7 @@ ], "data": [ "str:DirectCall", - "str:withdrawInactiveStake", - "1,000,000,000" + "str:delegation withdraw inactive stake" ] }, { diff --git a/test/delegation/v0_3/test/integration/main/10_unbond_nodes.steps.json b/test/delegation/v0_3/test/integration/main/10_unbond_nodes.steps.json index fa6d097e4..339611618 100644 --- a/test/delegation/v0_3/test/integration/main/10_unbond_nodes.steps.json +++ b/test/delegation/v0_3/test/integration/main/10_unbond_nodes.steps.json @@ -46,9 +46,21 @@ "sc:delegation" ], "data": [ - "str:AsyncCall", - "str:unBond", - "str:bls_key_5_______________________________________________________________________________________" + "str:BackTransfer", + "0" + ] + }, + { + "address": "sc:auction", + "endpoint": "str:transferValueOnly", + "topics": [ + "111,000,000,000,000", + "sc:delegation" + ], + "data": [ + "str:AsyncCallback", + "str:callBack", + "0x00" ] }, { diff --git a/test/delegation/v0_3/test/integration/main/15_unbond_all.steps.json b/test/delegation/v0_3/test/integration/main/15_unbond_all.steps.json index 8562a9e77..38f2d5111 100644 --- a/test/delegation/v0_3/test/integration/main/15_unbond_all.steps.json +++ b/test/delegation/v0_3/test/integration/main/15_unbond_all.steps.json @@ -46,11 +46,21 @@ "sc:delegation" ], "data": [ - "str:AsyncCall", - "str:unBond", - "str:bls_key_6_______________________________________________________________________________________", - "str:bls_key_3_______________________________________________________________________________________", - "str:bls_key_2_______________________________________________________________________________________" + "str:BackTransfer", + "0" + ] + }, + { + "address": "sc:auction", + "endpoint": "str:transferValueOnly", + "topics": [ + "333,000,000,000,000", + "sc:delegation" + ], + "data": [ + "str:AsyncCallback", + "str:callBack", + "0x00" ] }, { diff --git a/test/delegation/v0_3/test/integration/main/16_withdraw.steps.json b/test/delegation/v0_3/test/integration/main/16_withdraw.steps.json index 844852971..0b0d9bc43 100644 --- a/test/delegation/v0_3/test/integration/main/16_withdraw.steps.json +++ b/test/delegation/v0_3/test/integration/main/16_withdraw.steps.json @@ -27,8 +27,7 @@ ], "data": [ "str:DirectCall", - "str:withdrawInactiveStake", - "1,000,000,000,000" + "str:delegation withdraw inactive stake" ] }, { @@ -105,8 +104,7 @@ ], "data": [ "str:DirectCall", - "str:withdrawInactiveStake", - "113,000,000,000,000" + "str:delegation withdraw inactive stake" ] }, { @@ -183,8 +181,7 @@ ], "data": [ "str:DirectCall", - "str:withdrawInactiveStake", - "284,000,000,000,000" + "str:delegation withdraw inactive stake" ] }, { diff --git a/test/delegation/v0_4_genesis/test/integration/genesis/05_rewards.steps.json b/test/delegation/v0_4_genesis/test/integration/genesis/05_rewards.steps.json index a178dd6f5..e47a32e9a 100644 --- a/test/delegation/v0_4_genesis/test/integration/genesis/05_rewards.steps.json +++ b/test/delegation/v0_4_genesis/test/integration/genesis/05_rewards.steps.json @@ -135,7 +135,7 @@ ], "data": [ "str:DirectCall", - "str:claimRewards" + "str:delegation rewards claim" ] } ], diff --git a/test/delegation/v0_4_genesis/test/integration/rounding_error/rounding_error.scen.json b/test/delegation/v0_4_genesis/test/integration/rounding_error/rounding_error.scen.json index f4fd9d7a8..a82b6b7dc 100644 --- a/test/delegation/v0_4_genesis/test/integration/rounding_error/rounding_error.scen.json +++ b/test/delegation/v0_4_genesis/test/integration/rounding_error/rounding_error.scen.json @@ -128,7 +128,7 @@ ], "data": [ "str:DirectCall", - "str:claimRewards" + "str:delegation rewards claim" ] } ] diff --git a/test/delegation/v0_5_latest_full/scenarios/activate_nodes.scen.json b/test/delegation/v0_5_latest_full/scenarios/activate_nodes.scen.json index 6fcfcf4e9..bbc8821b8 100644 --- a/test/delegation/v0_5_latest_full/scenarios/activate_nodes.scen.json +++ b/test/delegation/v0_5_latest_full/scenarios/activate_nodes.scen.json @@ -273,9 +273,21 @@ "sc:delegation" ], "data": [ - "str:AsyncCall", - "str:unBondNodes", - "str:bls_key_6_______________________________________________________________________________________" + "str:BackTransfer", + "0" + ] + }, + { + "address": "sc:auction", + "endpoint": "str:transferValueOnly", + "topics": [ + "100,000,000,000,000", + "sc:delegation" + ], + "data": [ + "str:AsyncCallback", + "str:callBack", + "0x00" ] }, { diff --git a/test/delegation/v0_5_latest_full/scenarios/unstake_tokens.scen.json b/test/delegation/v0_5_latest_full/scenarios/unstake_tokens.scen.json index 9fabe1389..5f1501447 100644 --- a/test/delegation/v0_5_latest_full/scenarios/unstake_tokens.scen.json +++ b/test/delegation/v0_5_latest_full/scenarios/unstake_tokens.scen.json @@ -150,9 +150,21 @@ "sc:delegation" ], "data": [ - "str:AsyncCall", - "str:unBondTokens", - "1000" + "str:BackTransfer", + "" + ] + }, + { + "address": "sc:auction", + "endpoint": "str:transferValueOnly", + "topics": [ + "1000", + "sc:delegation" + ], + "data": [ + "str:AsyncCallback", + "str:callBack", + "0x00" ] } ], diff --git a/test/dns/scenarios/04_register_name_again.steps.json b/test/dns/scenarios/04_register_name_again.steps.json index 564241c37..f7e511fbd 100644 --- a/test/dns/scenarios/04_register_name_again.steps.json +++ b/test/dns/scenarios/04_register_name_again.steps.json @@ -35,7 +35,7 @@ }, { "step": "scCall", - "id": "resolve-coolname0001-again", + "id": "resolve-coolname0001-#2", "tx": { "from": "address:viewer", "to": "sc:dns#87", diff --git a/test/dns/scenarios/05_claim.steps.json b/test/dns/scenarios/05_claim.steps.json index 02d25e365..3bc926cc0 100644 --- a/test/dns/scenarios/05_claim.steps.json +++ b/test/dns/scenarios/05_claim.steps.json @@ -25,7 +25,7 @@ ], "data": [ "str:DirectCall", - "str:claim" + "str:dns claim" ] } ], diff --git a/test/dns/scenarios/06_register_other_name_same_shard.steps.json b/test/dns/scenarios/06_register_other_name_same_shard.steps.json index 895fbb9f5..c076c39be 100644 --- a/test/dns/scenarios/06_register_other_name_same_shard.steps.json +++ b/test/dns/scenarios/06_register_other_name_same_shard.steps.json @@ -26,7 +26,7 @@ }, { "step": "scCall", - "id": "resolve-coolname0001-again", + "id": "resolve-coolname0001-#3", "tx": { "from": "address:viewer", "to": "sc:dns#87", diff --git a/test/features/big-float-features/scenarios/big_float_operator_checks.scen.json b/test/features/big-float-features/scenarios/big_float_operator_checks.scen.json index a3a9e8e51..4fca5f02d 100644 --- a/test/features/big-float-features/scenarios/big_float_operator_checks.scen.json +++ b/test/features/big-float-features/scenarios/big_float_operator_checks.scen.json @@ -17,7 +17,7 @@ }, { "step": "scCall", - "id": "BigFloatAdd - 3", + "id": "BigFloatAdd - 1", "tx": { "from": "address:an_account", "to": "sc:basic-features", @@ -37,7 +37,7 @@ }, { "step": "scCall", - "id": "BigFloatAdd - 4", + "id": "BigFloatAdd - 2", "tx": { "from": "address:an_account", "to": "sc:basic-features", diff --git a/test/features/composability/builtin-func-features/output/builtin-func-features.wasm b/test/features/composability/builtin-func-features/output/builtin-func-features.wasm new file mode 100755 index 000000000..2e17eb18d Binary files /dev/null and b/test/features/composability/builtin-func-features/output/builtin-func-features.wasm differ diff --git a/test/features/composability/forwarder-raw/output/forwarder-raw-init-async-call.wasm b/test/features/composability/forwarder-raw/output/forwarder-raw-init-async-call.wasm index b95e9cf76..d8db3fd2e 100755 Binary files a/test/features/composability/forwarder-raw/output/forwarder-raw-init-async-call.wasm and b/test/features/composability/forwarder-raw/output/forwarder-raw-init-async-call.wasm differ diff --git a/test/features/composability/forwarder-raw/output/forwarder-raw-init-sync-call.wasm b/test/features/composability/forwarder-raw/output/forwarder-raw-init-sync-call.wasm index 9d40a6051..001bf0984 100755 Binary files a/test/features/composability/forwarder-raw/output/forwarder-raw-init-sync-call.wasm and b/test/features/composability/forwarder-raw/output/forwarder-raw-init-sync-call.wasm differ diff --git a/test/features/composability/forwarder-raw/output/forwarder-raw.wasm b/test/features/composability/forwarder-raw/output/forwarder-raw.wasm index 1339753a5..ed575905a 100755 Binary files a/test/features/composability/forwarder-raw/output/forwarder-raw.wasm and b/test/features/composability/forwarder-raw/output/forwarder-raw.wasm differ diff --git a/test/features/composability/forwarder/output/forwarder.wasm b/test/features/composability/forwarder/output/forwarder.wasm index 17061a705..dfd5b547a 100755 Binary files a/test/features/composability/forwarder/output/forwarder.wasm and b/test/features/composability/forwarder/output/forwarder.wasm differ diff --git a/test/features/composability/promises-features/output/promises-features.wasm b/test/features/composability/promises-features/output/promises-features.wasm index 0e4fa7aee..fcb20dceb 100755 Binary files a/test/features/composability/promises-features/output/promises-features.wasm and b/test/features/composability/promises-features/output/promises-features.wasm differ diff --git a/test/features/composability/proxy-test-first/output/proxy-test-first-unmanaged.wasm b/test/features/composability/proxy-test-first/output/proxy-test-first-unmanaged.wasm new file mode 100755 index 000000000..b9fbe0b33 Binary files /dev/null and b/test/features/composability/proxy-test-first/output/proxy-test-first-unmanaged.wasm differ diff --git a/test/features/composability/proxy-test-first/output/proxy-test-first.wasm b/test/features/composability/proxy-test-first/output/proxy-test-first.wasm index b1a785150..566ad44e7 100755 Binary files a/test/features/composability/proxy-test-first/output/proxy-test-first.wasm and b/test/features/composability/proxy-test-first/output/proxy-test-first.wasm differ diff --git a/test/features/composability/proxy-test-second/output/proxy-test-second.wasm b/test/features/composability/proxy-test-second/output/proxy-test-second.wasm index 9e19bc39f..e6c184f85 100755 Binary files a/test/features/composability/proxy-test-second/output/proxy-test-second.wasm and b/test/features/composability/proxy-test-second/output/proxy-test-second.wasm differ diff --git a/test/features/composability/recursive-caller/output/recursive-caller.wasm b/test/features/composability/recursive-caller/output/recursive-caller.wasm index 447445901..0bfd743f9 100755 Binary files a/test/features/composability/recursive-caller/output/recursive-caller.wasm and b/test/features/composability/recursive-caller/output/recursive-caller.wasm differ diff --git a/test/features/composability/scenarios-promises/promises_call_async_retrieve_egld.scen.json b/test/features/composability/scenarios-promises/promises_call_async_retrieve_egld.scen.json index 671b24c0c..de22eeabf 100644 --- a/test/features/composability/scenarios-promises/promises_call_async_retrieve_egld.scen.json +++ b/test/features/composability/scenarios-promises/promises_call_async_retrieve_egld.scen.json @@ -75,11 +75,21 @@ "sc:forwarder" ], "data": [ - "str:AsyncCall", - "str:retrieve_funds", - "str:EGLD", - "0", - "1000" + "str:BackTransfer", + "" + ] + }, + { + "address": "sc:vault", + "endpoint": "str:transferValueOnly", + "topics": [ + "1000", + "sc:forwarder" + ], + "data": [ + "str:AsyncCallback", + "str:retrieve_funds_callback", + "0x00" ] }, { diff --git a/test/features/composability/scenarios-promises/promises_call_async_retrieve_esdt.scen.json b/test/features/composability/scenarios-promises/promises_call_async_retrieve_esdt.scen.json index 76489b6f1..be292d045 100644 --- a/test/features/composability/scenarios-promises/promises_call_async_retrieve_esdt.scen.json +++ b/test/features/composability/scenarios-promises/promises_call_async_retrieve_esdt.scen.json @@ -80,7 +80,7 @@ "sc:forwarder" ], "data": [ - "str:AsyncCall", + "str:BackTransfer", "str:ESDTTransfer", "str:TEST-TOKENA", "1000" diff --git a/test/features/composability/scenarios/builtin_func_delete_user_name.scen.json b/test/features/composability/scenarios/builtin_func_delete_user_name.scen.json new file mode 100644 index 000000000..7414fa587 --- /dev/null +++ b/test/features/composability/scenarios/builtin_func_delete_user_name.scen.json @@ -0,0 +1,59 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "address:user-a": { + "nonce": "0", + "balance": "0" + }, + "address:user-b": { + "nonce": "0", + "balance": "0", + "username": "str:old-name" + }, + "sc:dns#00": { + "nonce": "0", + "balance": "0", + "code": "file:../builtin-func-features/output/builtin-func-features.wasm" + } + } + }, + { + "step": "scCall", + "id": "1", + "tx": { + "from": "address:user-a", + "to": "sc:dns#00", + "function": "call_delete_user_name", + "arguments": [ + "address:user-b" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0" + } + }, + { + "step": "checkState", + "accounts": { + "address:user-a": { + "nonce": "1", + "balance": "0" + }, + "address:user-b": { + "nonce": "0", + "balance": "0", + "username": "" + }, + "sc:dns#00": { + "nonce": "0", + "balance": "0", + "code": "file:../builtin-func-features/output/builtin-func-features.wasm" + } + } + } + ] +} diff --git a/test/features/composability/scenarios/builtin_func_set_user_name.scen.json b/test/features/composability/scenarios/builtin_func_set_user_name.scen.json new file mode 100644 index 000000000..e52de6e93 --- /dev/null +++ b/test/features/composability/scenarios/builtin_func_set_user_name.scen.json @@ -0,0 +1,59 @@ +{ + "steps": [ + { + "step": "setState", + "accounts": { + "address:user-a": { + "nonce": "0", + "balance": "0" + }, + "address:user-b": { + "nonce": "0", + "balance": "0" + }, + "sc:dns#00": { + "nonce": "0", + "balance": "0", + "code": "file:../builtin-func-features/output/builtin-func-features.wasm" + } + } + }, + { + "step": "scCall", + "id": "1", + "tx": { + "from": "address:user-a", + "to": "sc:dns#00", + "function": "call_set_user_name", + "arguments": [ + "address:user-b", + "str:new-name" + ], + "gasLimit": "50,000,000", + "gasPrice": "0" + }, + "expect": { + "status": "0" + } + }, + { + "step": "checkState", + "accounts": { + "address:user-a": { + "nonce": "1", + "balance": "0" + }, + "address:user-b": { + "nonce": "0", + "balance": "0", + "username": "str:new-name" + }, + "sc:dns#00": { + "nonce": "0", + "balance": "0", + "code": "file:../builtin-func-features/output/builtin-func-features.wasm" + } + } + } + ] +} diff --git a/test/features/composability/scenarios/forwarder_call_async_retrieve_egld.scen.json b/test/features/composability/scenarios/forwarder_call_async_retrieve_egld.scen.json index 7537edd04..ee603e98d 100644 --- a/test/features/composability/scenarios/forwarder_call_async_retrieve_egld.scen.json +++ b/test/features/composability/scenarios/forwarder_call_async_retrieve_egld.scen.json @@ -76,11 +76,21 @@ "sc:forwarder" ], "data": [ - "str:AsyncCall", - "str:retrieve_funds", - "str:EGLD", - "0", - "1000" + "str:BackTransfer", + "0" + ] + }, + { + "address": "sc:vault", + "endpoint": "str:transferValueOnly", + "topics": [ + "1000", + "sc:forwarder" + ], + "data": [ + "str:AsyncCallback", + "str:callBack", + "0x00" ] }, { diff --git a/test/features/composability/scenarios/forwarder_call_async_retrieve_esdt.scen.json b/test/features/composability/scenarios/forwarder_call_async_retrieve_esdt.scen.json index af660b7cf..0e386ad6d 100644 --- a/test/features/composability/scenarios/forwarder_call_async_retrieve_esdt.scen.json +++ b/test/features/composability/scenarios/forwarder_call_async_retrieve_esdt.scen.json @@ -81,7 +81,7 @@ "sc:forwarder" ], "data": [ - "str:AsyncCall", + "str:BackTransfer", "str:ESDTTransfer", "str:TEST-TOKENA", "1000" diff --git a/test/features/composability/scenarios/forwarder_call_async_retrieve_nft.scen.json b/test/features/composability/scenarios/forwarder_call_async_retrieve_nft.scen.json index 3362b0960..48a326c28 100644 --- a/test/features/composability/scenarios/forwarder_call_async_retrieve_nft.scen.json +++ b/test/features/composability/scenarios/forwarder_call_async_retrieve_nft.scen.json @@ -88,7 +88,7 @@ "sc:forwarder" ], "data": [ - "str:AsyncCall", + "str:BackTransfer", "str:ESDTNFTTransfer", "str:NFT-000001", "5", diff --git a/test/features/composability/scenarios/forwarder_call_sync_retrieve_egld.scen.json b/test/features/composability/scenarios/forwarder_call_sync_retrieve_egld.scen.json index b8e67c365..38a45c7e2 100644 --- a/test/features/composability/scenarios/forwarder_call_sync_retrieve_egld.scen.json +++ b/test/features/composability/scenarios/forwarder_call_sync_retrieve_egld.scen.json @@ -76,11 +76,8 @@ "sc:forwarder" ], "data": [ - "str:ExecuteOnDestContext", - "str:retrieve_funds", - "str:EGLD", - "0", - "1000" + "str:BackTransfer", + "0" ] } ], diff --git a/test/features/composability/scenarios/forwarder_call_sync_retrieve_esdt.scen.json b/test/features/composability/scenarios/forwarder_call_sync_retrieve_esdt.scen.json index 622c58b09..31ad91a9f 100644 --- a/test/features/composability/scenarios/forwarder_call_sync_retrieve_esdt.scen.json +++ b/test/features/composability/scenarios/forwarder_call_sync_retrieve_esdt.scen.json @@ -81,7 +81,7 @@ "sc:forwarder" ], "data": [ - "str:ExecuteOnDestContext", + "str:BackTransfer", "str:ESDTTransfer", "str:TEST-TOKENA", "1000" diff --git a/test/features/composability/scenarios/forwarder_call_sync_retrieve_nft.scen.json b/test/features/composability/scenarios/forwarder_call_sync_retrieve_nft.scen.json index 65aa6d891..c326dbe98 100644 --- a/test/features/composability/scenarios/forwarder_call_sync_retrieve_nft.scen.json +++ b/test/features/composability/scenarios/forwarder_call_sync_retrieve_nft.scen.json @@ -88,7 +88,7 @@ "sc:forwarder" ], "data": [ - "str:ExecuteOnDestContext", + "str:BackTransfer", "str:ESDTNFTTransfer", "str:NFT-000001", "5", diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld.scen.json index ceb1c5333..cba3a8d45 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld.scen.json @@ -46,7 +46,7 @@ "sc:vault" ], "data": [ - "str:ExecuteOnDestContext", + "str:TransferAndExecute", "str:accept_funds" ] }, diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld_twice.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld_twice.scen.json index 9506a63af..f4e1776e6 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld_twice.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_egld_twice.scen.json @@ -46,7 +46,7 @@ "sc:vault" ], "data": [ - "str:ExecuteOnDestContext", + "str:TransferAndExecute", "str:accept_funds" ] }, @@ -69,7 +69,7 @@ "sc:vault" ], "data": [ - "str:ExecuteOnDestContext", + "str:TransferAndExecute", "str:accept_funds" ] }, diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt.scen.json index 614365bca..80f8d48e0 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt.scen.json @@ -56,10 +56,11 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTTransfer", "str:TEST-TOKENA", - "1000" + "1000", + "str:accept_funds" ] }, { diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt_twice.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt_twice.scen.json index f5b6facdd..2bce23a32 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt_twice.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_esdt_twice.scen.json @@ -56,10 +56,11 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTTransfer", "str:TEST-TOKENA", - "1000" + "1000", + "str:accept_funds" ] }, { @@ -86,10 +87,11 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTTransfer", "str:TEST-TOKENA", - "1000" + "1000", + "str:accept_funds" ] }, { diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_multi_transfer.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_multi_transfer.scen.json index 7896a3a7d..2c5afabb3 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_multi_transfer.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_multi_transfer.scen.json @@ -77,7 +77,7 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:MultiESDTNFTTransfer", "sc:vault", "2", @@ -86,7 +86,8 @@ "100", "str:FWD-TOKEN", "0", - "200" + "200", + "str:accept_funds" ] }, { diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_nft.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_nft.scen.json index b76f0f3d7..50be94968 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_nft.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_nft.scen.json @@ -64,12 +64,13 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTNFTTransfer", "str:NFT-000001", "5", "1", - "sc:vault" + "sc:vault", + "str:accept_funds" ] }, { diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_return_values.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_return_values.scen.json index e1cb0af7f..48207088b 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_return_values.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_return_values.scen.json @@ -51,7 +51,7 @@ "sc:vault" ], "data": [ - "str:ExecuteOnDestContext", + "str:TransferAndExecute", "str:accept_funds" ] }, diff --git a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_sft_twice.scen.json b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_sft_twice.scen.json index 6a907dcda..9a4ad571d 100644 --- a/test/features/composability/scenarios/forwarder_call_transf_exec_accept_sft_twice.scen.json +++ b/test/features/composability/scenarios/forwarder_call_transf_exec_accept_sft_twice.scen.json @@ -64,12 +64,13 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTNFTTransfer", "str:NFT-000001", "5", "1", - "sc:vault" + "sc:vault", + "str:accept_funds" ] }, { @@ -96,12 +97,13 @@ "sc:vault" ], "data": [ - "str:DirectCall", + "str:TransferAndExecute", "str:ESDTNFTTransfer", "str:NFT-000001", "5", "1", - "sc:vault" + "sc:vault", + "str:accept_funds" ] }, { diff --git a/test/features/composability/vault/output/vault-promises.wasm b/test/features/composability/vault/output/vault-promises.wasm new file mode 100755 index 000000000..67a839149 Binary files /dev/null and b/test/features/composability/vault/output/vault-promises.wasm differ diff --git a/test/features/composability/vault/output/vault.wasm b/test/features/composability/vault/output/vault.wasm index ceb132537..2f000efc4 100755 Binary files a/test/features/composability/vault/output/vault.wasm and b/test/features/composability/vault/output/vault.wasm differ diff --git a/testcommon/instanceSmartContractCreatorTest.go b/testcommon/instanceSmartContractCreatorTest.go index 3a4350038..ae6f6863c 100644 --- a/testcommon/instanceSmartContractCreatorTest.go +++ b/testcommon/instanceSmartContractCreatorTest.go @@ -73,16 +73,23 @@ func (template *InstanceCreatorTestTemplate) WithSetup(setup func(vmhost.VMHost, // AndAssertResults provides the function that will aserts the results func (template *InstanceCreatorTestTemplate) AndAssertResults(assertResults func(*contextmock.BlockchainHookStub, *VMOutputVerifier)) { template.assertResults = assertResults - template.runTest(true) + template.runTestWithVerification(true) } // AndAssertResultsWithoutReset provides the function that will aserts the results func (template *InstanceCreatorTestTemplate) AndAssertResultsWithoutReset(assertResults func(*contextmock.BlockchainHookStub, *VMOutputVerifier)) { template.assertResults = assertResults - template.runTest(false) + template.runTestWithVerification(false) } -func (template *InstanceCreatorTestTemplate) runTest(reset bool) { +func (template *InstanceCreatorTestTemplate) runTestWithVerification(reset bool) { + blhookStub, vmOutput, err := template.RunTest(reset) + verify := NewVMOutputVerifier(template.tb, vmOutput, err) + template.assertResults(blhookStub, verify) +} + +// RunTest executes the built test directly, without any assertions. +func (template *InstanceCreatorTestTemplate) RunTest(reset bool) (*contextmock.BlockchainHookStub, *vmcommon.VMOutput, error) { var blhookStub *contextmock.BlockchainHookStub if template.host == nil { blhookStub = template.createBlockchainStub() @@ -90,6 +97,7 @@ func (template *InstanceCreatorTestTemplate) runTest(reset bool) { template.host = template.hostBuilder.Build() template.setup(template.host, blhookStub) } + defer func() { if reset { template.host.Reset() @@ -102,8 +110,7 @@ func (template *InstanceCreatorTestTemplate) runTest(reset bool) { vmOutput, err := template.host.RunSmartContractCreate(template.input) - verify := NewVMOutputVerifier(template.tb, vmOutput, err) - template.assertResults(blhookStub, verify) + return blhookStub, vmOutput, err } func (template *InstanceCreatorTestTemplate) createBlockchainStub() *contextmock.BlockchainHookStub { diff --git a/testcommon/mockSmartContractCallerTest.go b/testcommon/mockSmartContractCallerTest.go index d97387b79..476a48a75 100644 --- a/testcommon/mockSmartContractCallerTest.go +++ b/testcommon/mockSmartContractCallerTest.go @@ -118,15 +118,36 @@ func (callerTest *MockInstancesTestTemplate) andAssertResultsWithWorld( if world == nil { world = worldmock.NewMockWorld() } - return callerTest.runTest(startNode, world, createAccount, testType, expectedErrorsForRound) + return callerTest.runTestAndVerify(startNode, world, createAccount, testType, expectedErrorsForRound) } -func (callerTest *MockInstancesTestTemplate) runTest( +func (callerTest *MockInstancesTestTemplate) runTestAndVerify( startNode *TestCallNode, world *worldmock.MockWorld, createContractAccounts bool, testType TestType, - expectedErrorsForRound []string) (*vmcommon.VMOutput, error) { + expectedErrorsForRound []string, +) (*vmcommon.VMOutput, error) { + host, vmOutput, err := callerTest.RunTest( + world, + createContractAccounts, + testType) + + allErrors := host.Runtime().GetAllErrors() + verify := NewVMOutputVerifierWithAllErrors(callerTest.tb, vmOutput, err, allErrors) + if callerTest.assertResults != nil { + callerTest.assertResults(startNode, world, verify, expectedErrorsForRound) + } + + return vmOutput, err +} + +// RunTest executes the built test directly, without any assertions. +func (callerTest *MockInstancesTestTemplate) RunTest( + world *worldmock.MockWorld, + createContractAccounts bool, + testType TestType, +) (vmhost.VMHost, *vmcommon.VMOutput, error) { if world == nil { world = worldmock.NewMockWorld() } @@ -162,13 +183,7 @@ func (callerTest *MockInstancesTestTemplate) runTest( }) } - allErrors := host.Runtime().GetAllErrors() - verify := NewVMOutputVerifierWithAllErrors(callerTest.tb, vmOutput, err, allErrors) - if callerTest.assertResults != nil { - callerTest.assertResults(startNode, world, verify, expectedErrorsForRound) - } - - return vmOutput, err + return host, vmOutput, err } // SimpleWasteGasMockMethod is a simple waste gas mock method diff --git a/testcommon/mockTestSmartContract.go b/testcommon/mockTestSmartContract.go index 773975743..0e73d08bc 100644 --- a/testcommon/mockTestSmartContract.go +++ b/testcommon/mockTestSmartContract.go @@ -11,7 +11,9 @@ var WasmVirtualMachine = []byte{5, 0} // TestConfig is configuration for async call tests type TestConfig struct { + ParentAddress []byte ChildAddress []byte + NephewAddress []byte ThirdPartyAddress []byte VaultAddress []byte diff --git a/vmhost/common.go b/vmhost/common.go index 682005e5b..0e511cae3 100644 --- a/vmhost/common.go +++ b/vmhost/common.go @@ -59,6 +59,39 @@ const ( // UnknownBreakpointString is the human-readable label for an unknown breakpoint value UnknownBreakpointString = "unknown breakpoint" + + // BackTransferString is the human-readable label for execution type + BackTransferString = "BackTransfer" + + // DirectCallString is the human-readable label for execution type + DirectCallString = "DirectCall" + + // ExecuteOnDestContextString is the human-readable label for execution type + ExecuteOnDestContextString = "ExecuteOnDestContext" + + // ExecuteOnSameContextString is the human-readable label for execution type + ExecuteOnSameContextString = "ExecuteOnSameContext" + + // AsyncCallString is the human-readable label for execution type + AsyncCallString = "AsyncCall" + + // AsyncCallbackString is the human-readable label for execution type + AsyncCallbackString = "AsyncCallback" + + // TransferAndExecuteString is the human-readable label for execution type + TransferAndExecuteString = "TransferAndExecute" + + // UpgradeFromSourceString is the human-readable label for execution type + UpgradeFromSourceString = "UpgradeFromSource" + + // TransferValueOnlyString is the human-readable label for transfer type + TransferValueOnlyString = "transferValueOnly" + + // DeploySmartContractString is the human-readable label for transfer type + DeploySmartContractString = "DeploySmartContract" + + // DeployFromSourceString is the human-readable label for transfer type + DeployFromSourceString = "DeployFromSource" ) // String returns the human-readable name of a BreakpointValue @@ -225,7 +258,8 @@ type AsyncGeneratedCall struct { } // OldAsyncContext is a structure containing a group of async calls and a callback -// that should be called when all these async calls are resolved +// +// that should be called when all these async calls are resolved type OldAsyncContext struct { Callback string AsyncCalls []*AsyncGeneratedCall @@ -261,9 +295,12 @@ func (ac *AsyncGeneratedCall) IsInterfaceNil() bool { return ac == nil } +// ESDTTransfersArgs defines the structure for ESDTTransferArgs, used in TransferAndExecute type ESDTTransfersArgs struct { Destination []byte OriginalCaller []byte Sender []byte Transfers []*vmcommon.ESDTTransfer + Function string + Arguments [][]byte } diff --git a/vmhost/contexts/async.go b/vmhost/contexts/async.go index f34d3ad3c..b90e87a0c 100644 --- a/vmhost/contexts/async.go +++ b/vmhost/contexts/async.go @@ -24,6 +24,7 @@ type asyncContext struct { marshalizer *marshal.GogoProtoMarshalizer originalCallerAddr []byte + parentAddr []byte callerAddr []byte callback string callbackData []byte @@ -73,6 +74,7 @@ func NewAsyncContext( stateStack: nil, originalCallerAddr: nil, callerAddr: nil, + parentAddr: nil, callback: "", callbackData: nil, gasAccumulated: 0, @@ -95,6 +97,7 @@ func (context *asyncContext) InitState() { context.callID = nil context.callerCallID = nil context.callerAddr = make([]byte, 0) + context.parentAddr = make([]byte, 0) context.gasAccumulated = 0 context.returnData = make([]byte, 0) context.asyncCallGroups = make([]*vmhost.AsyncCallGroup, 0) @@ -121,6 +124,9 @@ func (context *asyncContext) InitStateFromInput(input *vmcommon.ContractCallInpu runtime := context.host.Runtime() context.address = runtime.GetContextAddress() + context.parentAddr = make([]byte, len(input.CallerAddr)) + copy(context.parentAddr, input.CallerAddr) + emptyStack := len(context.stateStack) == 0 if emptyStack && !context.isCallAsync() { context.callID = input.CurrentTxHash @@ -138,6 +144,16 @@ func (context *asyncContext) InitStateFromInput(input *vmcommon.ContractCallInpu context.gasAccumulated = input.AsyncArguments.GasAccumulated } + if input.CallType == vm.AsynchronousCallBack { + asyncParentAddr, err := context.getParentAddressFromStorage() + if err != nil { + return err + } + + context.parentAddr = make([]byte, len(asyncParentAddr)) + copy(context.parentAddr, asyncParentAddr) + } + if logAsync.GetLevel() == logger.LogTrace { logAsync.Trace("Calling", "function", input.Function) logAsync.Trace("", "address", string(context.address)) @@ -148,6 +164,7 @@ func (context *asyncContext) InitStateFromInput(input *vmcommon.ContractCallInpu logAsync.Trace("", "callerCallID", context.callerCallID) logAsync.Trace("", "callbackAsyncInitiatorCallID", context.callbackAsyncInitiatorCallID) logAsync.Trace("", "gasAccumulated", context.gasAccumulated) + logAsync.Trace("", "parentAddress", string(context.parentAddr)) } return nil @@ -161,6 +178,7 @@ func (context *asyncContext) PushState() { callID: context.callID, callerCallID: context.callerCallID, callerAddr: context.callerAddr, + parentAddr: context.parentAddr, callback: context.callback, callbackData: context.callbackData, gasAccumulated: context.gasAccumulated, @@ -209,6 +227,7 @@ func (context *asyncContext) PopSetActiveState() { context.originalCallerAddr = prevState.originalCallerAddr context.callerAddr = prevState.callerAddr + context.parentAddr = prevState.parentAddr context.callerCallID = prevState.callerCallID context.callType = prevState.callType context.callbackAsyncInitiatorCallID = prevState.callbackAsyncInitiatorCallID @@ -227,6 +246,7 @@ func (context *asyncContext) Clone() vmhost.AsyncContext { return &asyncContext{ address: context.address, callerAddr: context.callerAddr, + parentAddr: context.parentAddr, originalCallerAddr: context.originalCallerAddr, callerCallID: context.callerCallID, callType: context.callType, @@ -262,6 +282,11 @@ func (context *asyncContext) GetCallerAddress() []byte { return context.callerAddr } +// GetParentAddress returns the address of the original caller. +func (context *asyncContext) GetParentAddress() []byte { + return context.parentAddr +} + // GetCallerCallID returns the callID of the original caller. func (context *asyncContext) GetCallerCallID() []byte { return context.callerCallID @@ -677,13 +702,28 @@ func (context *asyncContext) Execute() error { } } } - - context.deleteCallGroupByID(vmhost.LegacyAsyncCallGroupID) } return nil } +func (context *asyncContext) getParentAddressFromStorage() ([]byte, error) { + stackContext := context.getContextFromStack(context.address, context.callbackAsyncInitiatorCallID) + if stackContext != nil { + return stackContext.parentAddr, nil + } + + loadedContext, err := readAsyncContextFromStorage( + context.host.Storage(), + context.address, context.callbackAsyncInitiatorCallID, + context.marshalizer) + if err != nil { + return nil, err + } + + return loadedContext.parentAddr, nil +} + // UpdateCurrentAsyncCallStatus detects the AsyncCall returning as callback, // extracts the ReturnCode from data provided by the destination call, and updates // the status of the AsyncCall with its value. @@ -706,48 +746,24 @@ func (context *asyncContext) UpdateCurrentAsyncCallStatus( context.callbackAsyncInitiatorCallID, context.marshalizer) if err != nil { - if err == vmhost.ErrNoStoredAsyncContextFound { - return getLegacyCallback(address, vmInput), true, nil - } else { - return nil, false, err - } + return nil, false, err } asyncCallInfo := loadedContext.GetAsyncCallByCallID(callID) call := asyncCallInfo.GetAsyncCall() err = asyncCallInfo.GetError() if err != nil { - if err == vmhost.ErrAsyncCallNotFound { - return getLegacyCallback(address, vmInput), true, nil - } else { - return nil, false, err - } + return nil, false, err } // The first argument of the callback is the return code of the destination call destReturnCode := big.NewInt(0).SetBytes(vmInput.Arguments[0]).Uint64() call.UpdateStatus(vmcommon.ReturnCode(destReturnCode)) - return call, false, nil -} - -func getLegacyCallback(address []byte, vmInput *vmcommon.VMInput) *vmhost.AsyncCall { - var valueBytes []byte = nil - if vmInput.CallValue != nil { - valueBytes = vmInput.CallValue.Bytes() - } - return &vmhost.AsyncCall{ - Status: vmhost.AsyncCallResolved, - Destination: address, - ValueBytes: valueBytes, - SuccessCallback: vmhost.CallbackFunctionName, - ErrorCallback: vmhost.CallbackFunctionName, - GasLimit: vmInput.GasProvided, - GasLocked: vmInput.GasLocked, - } + return call, loadedContext.HasLegacyGroup(), nil } -func (context *asyncContext) isMultiLevelAsync(call *vmhost.AsyncCall) bool { +func (context *asyncContext) isMultiLevelAsync(_ *vmhost.AsyncCall) bool { return context.isCallAsyncOnStack() } @@ -917,7 +933,11 @@ func (context *asyncContext) determineExecutionMode(call *vmhost.AsyncCall) (vmh return vmhost.AsyncUnknown, nil } - actualDestination := context.determineDestinationForAsyncCall(destination, data) + actualDestination, err := context.determineDestinationForAsyncCall(destination, data) + if err != nil { + return vmhost.AsyncUnknown, err + } + sameShard := context.host.AreInSameShard(runtime.GetContextAddress(), actualDestination) if context.host.IsBuiltinFunctionName(functionName) { if sameShard { @@ -934,26 +954,27 @@ func (context *asyncContext) determineExecutionMode(call *vmhost.AsyncCall) (vmh return vmhost.AsyncUnknown, nil } -func (context *asyncContext) determineDestinationForAsyncCall(destination []byte, data []byte) []byte { +func (context *asyncContext) determineDestinationForAsyncCall(destination []byte, data []byte) ([]byte, error) { if !bytes.Equal(context.host.Runtime().GetContextAddress(), destination) { - return destination + return destination, nil } argsParser := context.callArgsParser functionName, args, err := argsParser.ParseData(string(data)) - // TODO(check) what should do if we have a not nil err - _ = err + if err != nil { + return nil, err + } if !context.host.IsBuiltinFunctionName(functionName) { - return destination + return destination, nil } parsedTransfer, err := context.esdtTransferParser.ParseESDTTransfers(destination, destination, functionName, args) if err != nil { - return destination + return destination, nil } - return parsedTransfer.RcvAddr + return parsedTransfer.RcvAddr, nil } func (context *asyncContext) findGroupByID(groupID string) (int, bool) { @@ -985,7 +1006,7 @@ func (context *asyncContext) accumulateGas(gas uint64) { logAsync.Trace("async gas accumulated", "gas", context.gasAccumulated) } -// HasLegacyGroup checks if the a legacy async group was created +// HasLegacyGroup checks if the legacy async group was created func (context *asyncContext) HasLegacyGroup() bool { _, hasLegacyGroup := context.GetCallGroup(vmhost.LegacyAsyncCallGroupID) return hasLegacyGroup diff --git a/vmhost/contexts/async.pb.go b/vmhost/contexts/async.pb.go index 2f3c3ebc3..9b554c3d4 100644 --- a/vmhost/contexts/async.pb.go +++ b/vmhost/contexts/async.pb.go @@ -474,16 +474,17 @@ type SerializableAsyncContext struct { CallID []byte `protobuf:"bytes,2,opt,name=CallID,proto3" json:"CallID,omitempty"` CallType SerializableCallType `protobuf:"varint,3,opt,name=CallType,proto3,enum=contexts.SerializableCallType" json:"CallType,omitempty"` CallerAddr []byte `protobuf:"bytes,4,opt,name=CallerAddr,proto3" json:"CallerAddr,omitempty"` - CallerCallID []byte `protobuf:"bytes,5,opt,name=CallerCallID,proto3" json:"CallerCallID,omitempty"` - CallbackAsyncInitiatorCallID []byte `protobuf:"bytes,6,opt,name=CallbackAsyncInitiatorCallID,proto3" json:"CallbackAsyncInitiatorCallID,omitempty"` - Callback string `protobuf:"bytes,7,opt,name=Callback,proto3" json:"Callback,omitempty"` - CallbackData []byte `protobuf:"bytes,8,opt,name=CallbackData,proto3" json:"CallbackData,omitempty"` - GasAccumulated uint64 `protobuf:"varint,9,opt,name=GasAccumulated,proto3" json:"GasAccumulated,omitempty"` - ReturnData []byte `protobuf:"bytes,10,opt,name=ReturnData,proto3" json:"ReturnData,omitempty"` - AsyncCallGroups []*vmhost.SerializableAsyncCallGroup `protobuf:"bytes,11,rep,name=asyncCallGroups,proto3" json:"asyncCallGroups,omitempty"` - CallsCounter uint64 `protobuf:"varint,12,opt,name=CallsCounter,proto3" json:"CallsCounter,omitempty"` - TotalCallsCounter uint64 `protobuf:"varint,13,opt,name=TotalCallsCounter,proto3" json:"TotalCallsCounter,omitempty"` - ChildResults *SerializableVMOutput `protobuf:"bytes,14,opt,name=ChildResults,proto3" json:"ChildResults,omitempty"` + ParentAddr []byte `protobuf:"bytes,5,opt,name=ParentAddr,proto3" json:"ParentAddr,omitempty"` + CallerCallID []byte `protobuf:"bytes,6,opt,name=CallerCallID,proto3" json:"CallerCallID,omitempty"` + CallbackAsyncInitiatorCallID []byte `protobuf:"bytes,7,opt,name=CallbackAsyncInitiatorCallID,proto3" json:"CallbackAsyncInitiatorCallID,omitempty"` + Callback string `protobuf:"bytes,8,opt,name=Callback,proto3" json:"Callback,omitempty"` + CallbackData []byte `protobuf:"bytes,9,opt,name=CallbackData,proto3" json:"CallbackData,omitempty"` + GasAccumulated uint64 `protobuf:"varint,10,opt,name=GasAccumulated,proto3" json:"GasAccumulated,omitempty"` + ReturnData []byte `protobuf:"bytes,11,opt,name=ReturnData,proto3" json:"ReturnData,omitempty"` + AsyncCallGroups []*vmhost.SerializableAsyncCallGroup `protobuf:"bytes,12,rep,name=asyncCallGroups,proto3" json:"asyncCallGroups,omitempty"` + CallsCounter uint64 `protobuf:"varint,13,opt,name=CallsCounter,proto3" json:"CallsCounter,omitempty"` + TotalCallsCounter uint64 `protobuf:"varint,14,opt,name=TotalCallsCounter,proto3" json:"TotalCallsCounter,omitempty"` + ChildResults *SerializableVMOutput `protobuf:"bytes,15,opt,name=ChildResults,proto3" json:"ChildResults,omitempty"` } func (m *SerializableAsyncContext) Reset() { *m = SerializableAsyncContext{} } @@ -542,6 +543,13 @@ func (m *SerializableAsyncContext) GetCallerAddr() []byte { return nil } +func (m *SerializableAsyncContext) GetParentAddr() []byte { + if m != nil { + return m.ParentAddr + } + return nil +} + func (m *SerializableAsyncContext) GetCallerCallID() []byte { if m != nil { return m.CallerCallID @@ -627,78 +635,78 @@ func init() { func init() { proto.RegisterFile("async.proto", fileDescriptor_83b2a03067ffcb1d) } var fileDescriptor_83b2a03067ffcb1d = []byte{ - // 1121 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4f, 0x6f, 0xe3, 0x44, - 0x14, 0x8f, 0xf3, 0xa7, 0x4d, 0x5f, 0xb2, 0x69, 0x99, 0xad, 0x2a, 0x13, 0xad, 0xdc, 0x28, 0xac, - 0x50, 0x84, 0xa8, 0x83, 0xca, 0x01, 0x58, 0x4e, 0x4d, 0x53, 0x55, 0x95, 0xda, 0x5d, 0xc9, 0xcd, - 0x2e, 0x62, 0x2f, 0x68, 0x62, 0x4f, 0x1c, 0xab, 0x8e, 0x27, 0xf2, 0x8c, 0xab, 0x06, 0x81, 0xc4, - 0x47, 0xe0, 0x63, 0x20, 0x3e, 0x00, 0x9f, 0x81, 0x63, 0x6f, 0xf4, 0x54, 0x68, 0x7a, 0x41, 0x3d, - 0xed, 0x07, 0xe0, 0x80, 0x66, 0x6c, 0x27, 0x9e, 0x34, 0x94, 0x3f, 0x5a, 0x4e, 0x9e, 0xf7, 0xf3, - 0x7b, 0x6f, 0xde, 0xbc, 0xf7, 0x7b, 0x6f, 0x06, 0x2a, 0x98, 0x4d, 0x02, 0xdb, 0x1c, 0x87, 0x94, - 0x53, 0x54, 0xb6, 0x69, 0xc0, 0xc9, 0x05, 0x67, 0xf5, 0xcf, 0x5d, 0x8f, 0x0f, 0xa3, 0xbe, 0x69, - 0xd3, 0x51, 0x7b, 0x14, 0xf9, 0xdc, 0x3b, 0x27, 0x21, 0xbb, 0x68, 0x8f, 0x2e, 0x76, 0xec, 0x21, - 0xf6, 0x82, 0x9d, 0xf3, 0xd1, 0x8e, 0x4b, 0xdb, 0xe7, 0xa3, 0x21, 0x65, 0xbc, 0x2d, 0x5d, 0xec, - 0x63, 0xdf, 0x8f, 0xdd, 0xd4, 0x77, 0x32, 0xc6, 0x2e, 0x75, 0x69, 0x5b, 0xc2, 0xfd, 0x68, 0x20, - 0x25, 0x29, 0xc8, 0x55, 0xac, 0xde, 0xbc, 0x2e, 0xc2, 0xe6, 0x29, 0x09, 0x3d, 0xec, 0x7b, 0x5f, - 0xe3, 0xbe, 0x4f, 0x5e, 0x9d, 0xbc, 0x88, 0xf8, 0x38, 0xe2, 0xc8, 0x00, 0xb0, 0x08, 0x8f, 0xc2, - 0xa0, 0x8b, 0x39, 0xd6, 0xb5, 0x46, 0xa1, 0x55, 0xb5, 0x32, 0xc8, 0xfc, 0xff, 0x3e, 0x75, 0x88, - 0x9e, 0x6f, 0x68, 0xad, 0xa2, 0x95, 0x41, 0xd0, 0x53, 0x78, 0x14, 0x4b, 0x27, 0x84, 0x31, 0xec, - 0x12, 0xbd, 0xd0, 0xd0, 0x5a, 0x6b, 0x96, 0x0a, 0xa2, 0x26, 0x54, 0x0f, 0x31, 0xb3, 0xc8, 0x08, - 0x7b, 0x81, 0x17, 0xb8, 0x7a, 0x51, 0xfa, 0x51, 0x30, 0x34, 0x86, 0x35, 0x29, 0x0f, 0xa2, 0xc0, - 0xd1, 0x4b, 0x0d, 0xad, 0x55, 0xed, 0x58, 0x77, 0xd7, 0xdb, 0xa5, 0x57, 0xd8, 0x8f, 0xc8, 0x8f, - 0xbf, 0x6e, 0x1f, 0x8c, 0x30, 0x1f, 0xb6, 0xfb, 0x9e, 0x6b, 0x1e, 0x05, 0xfc, 0xef, 0x72, 0x67, - 0xd3, 0x90, 0x88, 0xec, 0x39, 0x98, 0x63, 0xb3, 0xe3, 0xb9, 0x47, 0x01, 0xdf, 0xc7, 0x8c, 0x93, - 0xd0, 0x9a, 0x6f, 0x82, 0x5e, 0x43, 0x2d, 0xce, 0xc2, 0x9e, 0x6d, 0xd3, 0x28, 0xe0, 0x4c, 0x5f, - 0x69, 0x14, 0x5a, 0x95, 0xdd, 0x5d, 0x33, 0xad, 0x91, 0xb9, 0x2c, 0x67, 0xa6, 0x6a, 0x74, 0x10, - 0xf0, 0x70, 0x62, 0x2d, 0x78, 0x42, 0x2d, 0x58, 0xef, 0x12, 0x9f, 0x70, 0xe2, 0xcc, 0x9c, 0xaf, - 0xca, 0xe4, 0x2e, 0xc2, 0x42, 0xb3, 0x47, 0x23, 0x7b, 0x98, 0xd1, 0x2c, 0xc7, 0x9a, 0x0b, 0x30, - 0xda, 0x85, 0xe2, 0x31, 0x75, 0x99, 0xbe, 0xd6, 0xd0, 0x5a, 0x95, 0x5d, 0x63, 0x79, 0x94, 0xc7, - 0xd4, 0x8d, 0x23, 0x92, 0xba, 0xf5, 0x01, 0x3c, 0x5e, 0x12, 0x2e, 0xda, 0x80, 0xc2, 0x19, 0x99, - 0xe8, 0x9a, 0x2c, 0x96, 0x58, 0xa2, 0xcf, 0xa0, 0x74, 0x2e, 0x32, 0x2d, 0x6b, 0x5c, 0xd9, 0x7d, - 0x6f, 0xb9, 0x77, 0xc5, 0x97, 0x15, 0x5b, 0x3c, 0xcb, 0x7f, 0xaa, 0x35, 0x7f, 0xca, 0x43, 0xfd, - 0xbe, 0x62, 0x2f, 0xc4, 0x01, 0x1b, 0x90, 0x10, 0x0d, 0x21, 0xae, 0xa3, 0xdc, 0xf1, 0xff, 0x29, - 0x6c, 0xec, 0x0f, 0xd5, 0xa1, 0x7c, 0x88, 0xd9, 0xb1, 0x37, 0xf2, 0x78, 0x42, 0xd7, 0x99, 0x8c, - 0x9e, 0x48, 0x8a, 0x1d, 0x53, 0xfb, 0x8c, 0x38, 0x92, 0xa8, 0x45, 0x6b, 0x0e, 0x20, 0x04, 0x45, - 0xd9, 0x04, 0x82, 0x9c, 0x55, 0x4b, 0xae, 0xd1, 0x33, 0x28, 0x8b, 0xa6, 0xeb, 0x4d, 0xc6, 0x44, - 0x72, 0xb2, 0xf6, 0x57, 0x69, 0x4f, 0xb5, 0xac, 0x99, 0xbe, 0x68, 0x8d, 0x53, 0x12, 0x38, 0x24, - 0xdc, 0x73, 0x9c, 0x90, 0x30, 0xc1, 0x2e, 0xe1, 0x58, 0x05, 0x9b, 0x18, 0xde, 0xcd, 0xfa, 0x39, - 0xe5, 0x34, 0xc4, 0x2e, 0x79, 0x39, 0x76, 0x30, 0x27, 0x68, 0x0b, 0x56, 0x5e, 0x0c, 0x06, 0x8c, - 0xf0, 0x38, 0x6f, 0x56, 0x22, 0xcd, 0x42, 0xcd, 0x67, 0x42, 0xd5, 0x61, 0xf5, 0x8b, 0xd0, 0xe3, - 0x9c, 0x04, 0xf2, 0x68, 0x65, 0x2b, 0x15, 0x9b, 0xbf, 0x94, 0xd4, 0x3d, 0x94, 0x22, 0x0a, 0xbb, - 0x34, 0xc0, 0x78, 0x93, 0x54, 0x44, 0x9b, 0x50, 0x7a, 0x4e, 0x03, 0x3b, 0x6d, 0xfb, 0x58, 0x40, - 0x01, 0xac, 0x76, 0xb0, 0x8f, 0x05, 0x5e, 0x90, 0xc5, 0xec, 0xdd, 0x5d, 0x6f, 0xa7, 0xd0, 0xdb, - 0x2b, 0x67, 0xea, 0x11, 0x7d, 0x05, 0x35, 0x25, 0x29, 0x4c, 0x2f, 0xca, 0x2e, 0xfd, 0xe4, 0x1f, - 0x30, 0xd4, 0x54, 0x2d, 0x93, 0x56, 0x55, 0x41, 0x91, 0x4c, 0x39, 0xdc, 0x4a, 0x71, 0x32, 0xe5, - 0x58, 0x6b, 0x42, 0x55, 0x7c, 0x4f, 0x08, 0xc7, 0x22, 0xb4, 0xa4, 0x74, 0x0a, 0x86, 0x3e, 0x82, - 0xc7, 0x42, 0xee, 0x92, 0xb1, 0x4f, 0x27, 0xf3, 0x2a, 0xaf, 0x4a, 0xd5, 0x65, 0xbf, 0xd0, 0xb7, - 0x50, 0x4d, 0x4e, 0xd5, 0x25, 0x3e, 0xc7, 0x7a, 0x59, 0xe6, 0xef, 0xcb, 0xbb, 0xeb, 0x6d, 0x05, - 0x7f, 0x7b, 0x49, 0x54, 0xdc, 0xa2, 0xe7, 0xb0, 0xae, 0xb6, 0xa5, 0x18, 0x25, 0x22, 0x95, 0x4f, - 0x1f, 0x4a, 0x65, 0xaa, 0x6c, 0x2d, 0x1a, 0x0b, 0xe6, 0x1c, 0x62, 0xf6, 0x92, 0x11, 0x47, 0x07, - 0xc9, 0x90, 0x54, 0x14, 0x53, 0x67, 0x49, 0xe6, 0xff, 0xf3, 0xd4, 0x51, 0x7c, 0x65, 0xa7, 0xce, - 0x37, 0xea, 0xad, 0x96, 0xce, 0x3e, 0x71, 0x6b, 0x1d, 0x39, 0x24, 0xe0, 0xde, 0xc0, 0x23, 0x61, - 0x42, 0xeb, 0x0c, 0x92, 0xe5, 0x7c, 0x5e, 0xe5, 0xfc, 0x16, 0xac, 0xf4, 0xe8, 0xd8, 0xb3, 0x99, - 0x5e, 0x90, 0x43, 0x38, 0x91, 0x96, 0x0d, 0x87, 0xe6, 0x1f, 0x45, 0xd0, 0xb3, 0xdb, 0xef, 0xc9, - 0x3b, 0x3a, 0x3e, 0xc0, 0x03, 0x6d, 0xb5, 0x05, 0x2b, 0x62, 0x46, 0x1c, 0x75, 0x93, 0xbd, 0x13, - 0x49, 0x99, 0x35, 0x85, 0x7f, 0x39, 0x6b, 0x0c, 0x00, 0xb1, 0x8e, 0xa9, 0x96, 0x04, 0x99, 0x41, - 0x24, 0x9f, 0xa5, 0x94, 0xec, 0x5c, 0x4a, 0xf8, 0x9c, 0xc1, 0x50, 0x07, 0x9e, 0x88, 0x55, 0x1f, - 0xdb, 0x67, 0xf2, 0x24, 0x47, 0x81, 0xc7, 0x3d, 0xcc, 0x69, 0x6a, 0x13, 0xf7, 0xc0, 0x83, 0x3a, - 0x62, 0xfa, 0xa6, 0xff, 0x65, 0x23, 0xac, 0x59, 0x33, 0x39, 0x8d, 0x41, 0xac, 0x65, 0x2a, 0xcb, - 0xf3, 0x18, 0x52, 0x0c, 0xbd, 0x0f, 0xb5, 0x43, 0xcc, 0xf6, 0x6c, 0x3b, 0x1a, 0x45, 0x3e, 0xe6, - 0xc4, 0x91, 0x97, 0x5d, 0xd1, 0x5a, 0x40, 0x17, 0x9e, 0x2d, 0x10, 0x9f, 0x37, 0xf3, 0x6c, 0x39, - 0x86, 0xf5, 0xd9, 0x8b, 0xe9, 0x30, 0xa4, 0xd1, 0x98, 0xe9, 0x15, 0x49, 0xf5, 0xa6, 0x19, 0x3f, - 0xa8, 0xcc, 0xfb, 0x85, 0x4b, 0x55, 0xad, 0x45, 0xd3, 0x34, 0x72, 0xb6, 0x2f, 0x66, 0x0a, 0x09, - 0xf5, 0x6a, 0xfc, 0x7c, 0xc9, 0x62, 0xe8, 0x43, 0x78, 0xa7, 0x47, 0x39, 0xf6, 0x15, 0xc5, 0x47, - 0x52, 0xf1, 0xfe, 0x0f, 0xd4, 0x81, 0xea, 0xfe, 0xd0, 0xf3, 0x1d, 0x8b, 0xb0, 0xc8, 0xe7, 0x4c, - 0xaf, 0x3d, 0x74, 0xa5, 0xa7, 0x0f, 0x0f, 0x4b, 0xb1, 0xf9, 0x20, 0x54, 0xc9, 0x3f, 0xe3, 0x42, - 0x0d, 0xa0, 0xeb, 0x85, 0xc4, 0xe6, 0x02, 0xd9, 0xc8, 0xa1, 0x4d, 0xd8, 0x90, 0x07, 0x1c, 0x86, - 0x34, 0xa0, 0x11, 0x93, 0xa8, 0x86, 0x74, 0xd8, 0x5c, 0x44, 0x3b, 0xd8, 0x3e, 0xdb, 0xc8, 0xa3, - 0x3a, 0x6c, 0x1d, 0x9c, 0x76, 0x7b, 0x69, 0x9f, 0xef, 0x05, 0xce, 0xc1, 0x05, 0xb1, 0x23, 0x4e, - 0x36, 0x0a, 0x9d, 0x83, 0xcb, 0x1b, 0x23, 0x77, 0x75, 0x63, 0xe4, 0xde, 0xdc, 0x18, 0xda, 0x77, - 0x53, 0x43, 0xfb, 0x61, 0x6a, 0x68, 0x3f, 0x4f, 0x0d, 0xed, 0x72, 0x6a, 0x68, 0x57, 0x53, 0x43, - 0xfb, 0x6d, 0x6a, 0x68, 0xbf, 0x4f, 0x8d, 0xdc, 0x9b, 0xa9, 0xa1, 0x7d, 0x7f, 0x6b, 0xe4, 0x2e, - 0x6f, 0x8d, 0xdc, 0xd5, 0xad, 0x91, 0x7b, 0x5d, 0x31, 0xcd, 0x76, 0x7a, 0xba, 0xfe, 0x8a, 0x7c, - 0x95, 0x7e, 0xfc, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x6e, 0xf5, 0xd9, 0x1a, 0x0b, 0x00, - 0x00, + // 1131 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x6e, 0x23, 0xc5, + 0x13, 0xf7, 0xf8, 0x23, 0x71, 0xca, 0x5e, 0x27, 0xff, 0xde, 0x28, 0x9a, 0xbf, 0xb5, 0x9a, 0x58, + 0x66, 0x85, 0x2c, 0x44, 0xc6, 0x28, 0x1c, 0x80, 0xe5, 0x14, 0xc7, 0x51, 0x14, 0x29, 0xd9, 0x45, + 0x13, 0xef, 0x22, 0xf6, 0x82, 0xda, 0x33, 0x6d, 0x7b, 0x94, 0xf1, 0xb4, 0x35, 0xdd, 0x13, 0x25, + 0x08, 0x24, 0x1e, 0x81, 0x07, 0xe0, 0x01, 0x10, 0x0f, 0xc0, 0x33, 0x70, 0xcc, 0x8d, 0x9c, 0x02, + 0x71, 0x2e, 0x28, 0xa7, 0x7d, 0x04, 0xd4, 0x3d, 0xd3, 0xce, 0xb4, 0x63, 0xc2, 0x87, 0x96, 0xd3, + 0x74, 0xfd, 0xba, 0xaa, 0xba, 0xba, 0xea, 0x57, 0x35, 0x0d, 0x15, 0xcc, 0xce, 0x43, 0xd7, 0x9e, + 0x44, 0x94, 0x53, 0x54, 0x76, 0x69, 0xc8, 0xc9, 0x19, 0x67, 0xf5, 0x4f, 0x87, 0x3e, 0x1f, 0xc5, + 0x7d, 0xdb, 0xa5, 0xe3, 0xf6, 0x38, 0x0e, 0xb8, 0x7f, 0x4a, 0x22, 0x76, 0xd6, 0x1e, 0x9f, 0x6d, + 0xb9, 0x23, 0xec, 0x87, 0x5b, 0xa7, 0xe3, 0xad, 0x21, 0x6d, 0x9f, 0x8e, 0x47, 0x94, 0xf1, 0xb6, + 0x74, 0xb1, 0x8b, 0x83, 0x20, 0x71, 0x53, 0xdf, 0xca, 0x18, 0x0f, 0xe9, 0x90, 0xb6, 0x25, 0xdc, + 0x8f, 0x07, 0x52, 0x92, 0x82, 0x5c, 0x25, 0xea, 0xcd, 0xab, 0x22, 0xac, 0x1f, 0x93, 0xc8, 0xc7, + 0x81, 0xff, 0x15, 0xee, 0x07, 0xe4, 0xd5, 0xd1, 0x8b, 0x98, 0x4f, 0x62, 0x8e, 0x2c, 0x00, 0x87, + 0xf0, 0x38, 0x0a, 0xbb, 0x98, 0x63, 0xd3, 0x68, 0x14, 0x5a, 0x55, 0x27, 0x83, 0xdc, 0xed, 0xef, + 0x52, 0x8f, 0x98, 0xf9, 0x86, 0xd1, 0x2a, 0x3a, 0x19, 0x04, 0x3d, 0x85, 0x47, 0x89, 0x74, 0x44, + 0x18, 0xc3, 0x43, 0x62, 0x16, 0x1a, 0x46, 0x6b, 0xc5, 0xd1, 0x41, 0xd4, 0x84, 0xea, 0x3e, 0x66, + 0x0e, 0x19, 0x63, 0x3f, 0xf4, 0xc3, 0xa1, 0x59, 0x94, 0x7e, 0x34, 0x0c, 0x4d, 0x60, 0x45, 0xca, + 0x83, 0x38, 0xf4, 0xcc, 0x52, 0xc3, 0x68, 0x55, 0x3b, 0xce, 0xed, 0xd5, 0x66, 0xe9, 0x15, 0x0e, + 0x62, 0xf2, 0xe3, 0xaf, 0x9b, 0x7b, 0x63, 0xcc, 0x47, 0xed, 0xbe, 0x3f, 0xb4, 0x0f, 0x42, 0xfe, + 0x57, 0xb9, 0x73, 0x69, 0x44, 0x44, 0xf6, 0x3c, 0xcc, 0xb1, 0xdd, 0xf1, 0x87, 0x07, 0x21, 0xdf, + 0xc5, 0x8c, 0x93, 0xc8, 0xb9, 0x3b, 0x04, 0xbd, 0x86, 0x5a, 0x92, 0x85, 0x1d, 0xd7, 0xa5, 0x71, + 0xc8, 0x99, 0xb9, 0xd4, 0x28, 0xb4, 0x2a, 0xdb, 0xdb, 0xb6, 0xaa, 0x91, 0xbd, 0x28, 0x67, 0xb6, + 0x6e, 0xb4, 0x17, 0xf2, 0xe8, 0xdc, 0x99, 0xf3, 0x84, 0x5a, 0xb0, 0xda, 0x25, 0x01, 0xe1, 0xc4, + 0x9b, 0x39, 0x5f, 0x96, 0xc9, 0x9d, 0x87, 0x85, 0x66, 0x8f, 0xc6, 0xee, 0x28, 0xa3, 0x59, 0x4e, + 0x34, 0xe7, 0x60, 0xb4, 0x0d, 0xc5, 0x43, 0x3a, 0x64, 0xe6, 0x4a, 0xc3, 0x68, 0x55, 0xb6, 0xad, + 0xc5, 0x51, 0x1e, 0xd2, 0x61, 0x12, 0x91, 0xd4, 0xad, 0x0f, 0xe0, 0xf1, 0x82, 0x70, 0xd1, 0x1a, + 0x14, 0x4e, 0xc8, 0xb9, 0x69, 0xc8, 0x62, 0x89, 0x25, 0xfa, 0x04, 0x4a, 0xa7, 0x22, 0xd3, 0xb2, + 0xc6, 0x95, 0xed, 0x77, 0x16, 0x7b, 0xd7, 0x7c, 0x39, 0x89, 0xc5, 0xb3, 0xfc, 0xc7, 0x46, 0xf3, + 0xa7, 0x3c, 0xd4, 0xef, 0x2b, 0xf6, 0x22, 0x1c, 0xb2, 0x01, 0x89, 0xd0, 0x08, 0x92, 0x3a, 0xca, + 0x13, 0xff, 0x9b, 0xc2, 0x26, 0xfe, 0x50, 0x1d, 0xca, 0xfb, 0x98, 0x1d, 0xfa, 0x63, 0x9f, 0xa7, + 0x74, 0x9d, 0xc9, 0xe8, 0x89, 0xa4, 0xd8, 0x21, 0x75, 0x4f, 0x88, 0x27, 0x89, 0x5a, 0x74, 0xee, + 0x00, 0x84, 0xa0, 0x28, 0x9b, 0x40, 0x90, 0xb3, 0xea, 0xc8, 0x35, 0x7a, 0x06, 0x65, 0xd1, 0x74, + 0xbd, 0xf3, 0x09, 0x91, 0x9c, 0xac, 0xfd, 0x59, 0xda, 0x95, 0x96, 0x33, 0xd3, 0x17, 0xad, 0x71, + 0x4c, 0x42, 0x8f, 0x44, 0x3b, 0x9e, 0x17, 0x11, 0x26, 0xd8, 0x25, 0x1c, 0xeb, 0x60, 0x13, 0xc3, + 0xff, 0xb3, 0x7e, 0x8e, 0x39, 0x8d, 0xf0, 0x90, 0xbc, 0x9c, 0x78, 0x98, 0x13, 0xb4, 0x01, 0x4b, + 0x2f, 0x06, 0x03, 0x46, 0x78, 0x92, 0x37, 0x27, 0x95, 0x66, 0xa1, 0xe6, 0x33, 0xa1, 0x9a, 0xb0, + 0xfc, 0x79, 0xe4, 0x73, 0x4e, 0x42, 0x79, 0xb5, 0xb2, 0xa3, 0xc4, 0xe6, 0x2f, 0x25, 0xfd, 0x0c, + 0xad, 0x88, 0xc2, 0x4e, 0x05, 0x98, 0x1c, 0xa2, 0x44, 0xb4, 0x0e, 0xa5, 0xe7, 0x34, 0x74, 0x55, + 0xdb, 0x27, 0x02, 0x0a, 0x61, 0xb9, 0x83, 0x03, 0x2c, 0xf0, 0x82, 0x2c, 0x66, 0xef, 0xf6, 0x6a, + 0x53, 0x41, 0x6f, 0xaf, 0x9c, 0xca, 0x23, 0xfa, 0x12, 0x6a, 0x5a, 0x52, 0x98, 0x59, 0x94, 0x5d, + 0xfa, 0xd1, 0xdf, 0x60, 0xa8, 0xad, 0x5b, 0xa6, 0xad, 0xaa, 0x83, 0x22, 0x99, 0x72, 0xb8, 0x95, + 0x92, 0x64, 0xca, 0xb1, 0xd6, 0x84, 0xaa, 0xf8, 0x1e, 0x11, 0x8e, 0x45, 0x68, 0x69, 0xe9, 0x34, + 0x0c, 0x7d, 0x00, 0x8f, 0x85, 0xdc, 0x25, 0x93, 0x80, 0x9e, 0xdf, 0x55, 0x79, 0x59, 0xaa, 0x2e, + 0xda, 0x42, 0xdf, 0x40, 0x35, 0xbd, 0x55, 0x97, 0x04, 0x1c, 0x9b, 0x65, 0x99, 0xbf, 0x2f, 0x6e, + 0xaf, 0x36, 0x35, 0xfc, 0xed, 0x25, 0x51, 0x73, 0x8b, 0x9e, 0xc3, 0xaa, 0xde, 0x96, 0x62, 0x94, + 0x88, 0x54, 0x3e, 0x7d, 0x28, 0x95, 0x4a, 0xd9, 0x99, 0x37, 0x16, 0xcc, 0xd9, 0xc7, 0xec, 0x25, + 0x23, 0x9e, 0x09, 0x92, 0x21, 0x4a, 0x14, 0x53, 0x67, 0x41, 0xe6, 0xff, 0xf5, 0xd4, 0xd1, 0x7c, + 0x65, 0xa7, 0xce, 0xd7, 0xfa, 0x5f, 0x4d, 0xcd, 0x3e, 0xf1, 0xd7, 0x3a, 0xf0, 0x48, 0xc8, 0xfd, + 0x81, 0x4f, 0xa2, 0x94, 0xd6, 0x19, 0x24, 0xcb, 0xf9, 0xbc, 0xce, 0xf9, 0x0d, 0x58, 0xea, 0xd1, + 0x89, 0xef, 0x32, 0xb3, 0x20, 0x87, 0x70, 0x2a, 0x2d, 0x1a, 0x0e, 0xcd, 0xef, 0x4b, 0x60, 0x66, + 0x8f, 0xdf, 0x91, 0xff, 0xe8, 0xe4, 0x02, 0x0f, 0xb4, 0xd5, 0x06, 0x2c, 0x89, 0x19, 0x71, 0xd0, + 0x4d, 0xcf, 0x4e, 0x25, 0x6d, 0xd6, 0x14, 0xfe, 0xe1, 0xac, 0xb1, 0x00, 0xc4, 0x3a, 0xa1, 0x5a, + 0x1a, 0x64, 0x06, 0x11, 0xfb, 0x9f, 0xe1, 0x88, 0x84, 0x5c, 0xee, 0x27, 0x4c, 0xcf, 0x20, 0x92, + 0xef, 0x52, 0x3b, 0x8d, 0x4c, 0xf1, 0x3d, 0x83, 0xa1, 0x0e, 0x3c, 0x11, 0xab, 0x3e, 0x76, 0x4f, + 0xe4, 0x4d, 0x0f, 0x42, 0x9f, 0xfb, 0x98, 0x53, 0x65, 0x93, 0x10, 0xff, 0x41, 0x1d, 0x31, 0x9d, + 0xd5, 0xbe, 0x64, 0xff, 0x8a, 0x33, 0x93, 0x55, 0x0c, 0x62, 0x2d, 0x53, 0xbd, 0x72, 0x17, 0x83, + 0xc2, 0xd0, 0xbb, 0x50, 0xdb, 0xc7, 0x6c, 0xc7, 0x75, 0xe3, 0x71, 0x1c, 0x60, 0x3e, 0x63, 0xde, + 0x1c, 0x3a, 0xf7, 0xac, 0xa9, 0x24, 0xf7, 0xcd, 0x3c, 0x6b, 0x0e, 0x61, 0x75, 0xf6, 0xa2, 0xda, + 0x8f, 0x68, 0x3c, 0x61, 0x66, 0x55, 0xb6, 0x42, 0xd3, 0x4e, 0x1e, 0x5c, 0xf6, 0xfd, 0xc2, 0x2a, + 0x55, 0x67, 0xde, 0x54, 0x45, 0xce, 0x76, 0xc5, 0xcc, 0x21, 0x91, 0xf9, 0x28, 0x79, 0xde, 0x64, + 0x31, 0xf4, 0x3e, 0xfc, 0xaf, 0x47, 0x39, 0x0e, 0x34, 0xc5, 0x9a, 0x54, 0xbc, 0xbf, 0x81, 0x3a, + 0x50, 0xdd, 0x1d, 0xf9, 0x81, 0xe7, 0x10, 0x16, 0x07, 0x9c, 0x99, 0xab, 0x0f, 0xfd, 0xf2, 0xd5, + 0xc3, 0xc4, 0xd1, 0x6c, 0xde, 0x8b, 0xf4, 0xe6, 0x98, 0x71, 0xa5, 0x06, 0xd0, 0xf5, 0x23, 0xe2, + 0x72, 0x81, 0xac, 0xe5, 0xd0, 0x3a, 0xac, 0xc9, 0x0b, 0x8e, 0x22, 0x1a, 0xd2, 0x98, 0x49, 0xd4, + 0x40, 0x26, 0xac, 0xcf, 0xa3, 0x1d, 0xec, 0x9e, 0xac, 0xe5, 0x51, 0x1d, 0x36, 0xf6, 0x8e, 0xbb, + 0x3d, 0x35, 0x07, 0x76, 0x42, 0x6f, 0xef, 0x8c, 0xb8, 0x31, 0x27, 0x6b, 0x85, 0xce, 0xde, 0xc5, + 0xb5, 0x95, 0xbb, 0xbc, 0xb6, 0x72, 0x6f, 0xae, 0x2d, 0xe3, 0xdb, 0xa9, 0x65, 0xfc, 0x30, 0xb5, + 0x8c, 0x9f, 0xa7, 0x96, 0x71, 0x31, 0xb5, 0x8c, 0xcb, 0xa9, 0x65, 0xfc, 0x36, 0xb5, 0x8c, 0xdf, + 0xa7, 0x56, 0xee, 0xcd, 0xd4, 0x32, 0xbe, 0xbb, 0xb1, 0x72, 0x17, 0x37, 0x56, 0xee, 0xf2, 0xc6, + 0xca, 0xbd, 0xae, 0xd8, 0x76, 0x5b, 0xdd, 0xae, 0xbf, 0x24, 0x5f, 0xad, 0x1f, 0xfe, 0x11, 0x00, + 0x00, 0xff, 0xff, 0x09, 0xb0, 0x39, 0x1d, 0x3a, 0x0b, 0x00, 0x00, } func (x SerializableCallType) String() string { @@ -987,6 +995,9 @@ func (this *SerializableAsyncContext) Equal(that interface{}) bool { if !bytes.Equal(this.CallerAddr, that1.CallerAddr) { return false } + if !bytes.Equal(this.ParentAddr, that1.ParentAddr) { + return false + } if !bytes.Equal(this.CallerCallID, that1.CallerCallID) { return false } @@ -1133,12 +1144,13 @@ func (this *SerializableAsyncContext) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 18) + s := make([]string, 0, 19) s = append(s, "&contexts.SerializableAsyncContext{") s = append(s, "Address: "+fmt.Sprintf("%#v", this.Address)+",\n") s = append(s, "CallID: "+fmt.Sprintf("%#v", this.CallID)+",\n") s = append(s, "CallType: "+fmt.Sprintf("%#v", this.CallType)+",\n") s = append(s, "CallerAddr: "+fmt.Sprintf("%#v", this.CallerAddr)+",\n") + s = append(s, "ParentAddr: "+fmt.Sprintf("%#v", this.ParentAddr)+",\n") s = append(s, "CallerCallID: "+fmt.Sprintf("%#v", this.CallerCallID)+",\n") s = append(s, "CallbackAsyncInitiatorCallID: "+fmt.Sprintf("%#v", this.CallbackAsyncInitiatorCallID)+",\n") s = append(s, "Callback: "+fmt.Sprintf("%#v", this.Callback)+",\n") @@ -1606,17 +1618,17 @@ func (m *SerializableAsyncContext) MarshalToSizedBuffer(dAtA []byte) (int, error i = encodeVarintAsync(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x72 + dAtA[i] = 0x7a } if m.TotalCallsCounter != 0 { i = encodeVarintAsync(dAtA, i, uint64(m.TotalCallsCounter)) i-- - dAtA[i] = 0x68 + dAtA[i] = 0x70 } if m.CallsCounter != 0 { i = encodeVarintAsync(dAtA, i, uint64(m.CallsCounter)) i-- - dAtA[i] = 0x60 + dAtA[i] = 0x68 } if len(m.AsyncCallGroups) > 0 { for iNdEx := len(m.AsyncCallGroups) - 1; iNdEx >= 0; iNdEx-- { @@ -1629,7 +1641,7 @@ func (m *SerializableAsyncContext) MarshalToSizedBuffer(dAtA []byte) (int, error i = encodeVarintAsync(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x5a + dAtA[i] = 0x62 } } if len(m.ReturnData) > 0 { @@ -1637,39 +1649,46 @@ func (m *SerializableAsyncContext) MarshalToSizedBuffer(dAtA []byte) (int, error copy(dAtA[i:], m.ReturnData) i = encodeVarintAsync(dAtA, i, uint64(len(m.ReturnData))) i-- - dAtA[i] = 0x52 + dAtA[i] = 0x5a } if m.GasAccumulated != 0 { i = encodeVarintAsync(dAtA, i, uint64(m.GasAccumulated)) i-- - dAtA[i] = 0x48 + dAtA[i] = 0x50 } if len(m.CallbackData) > 0 { i -= len(m.CallbackData) copy(dAtA[i:], m.CallbackData) i = encodeVarintAsync(dAtA, i, uint64(len(m.CallbackData))) i-- - dAtA[i] = 0x42 + dAtA[i] = 0x4a } if len(m.Callback) > 0 { i -= len(m.Callback) copy(dAtA[i:], m.Callback) i = encodeVarintAsync(dAtA, i, uint64(len(m.Callback))) i-- - dAtA[i] = 0x3a + dAtA[i] = 0x42 } if len(m.CallbackAsyncInitiatorCallID) > 0 { i -= len(m.CallbackAsyncInitiatorCallID) copy(dAtA[i:], m.CallbackAsyncInitiatorCallID) i = encodeVarintAsync(dAtA, i, uint64(len(m.CallbackAsyncInitiatorCallID))) i-- - dAtA[i] = 0x32 + dAtA[i] = 0x3a } if len(m.CallerCallID) > 0 { i -= len(m.CallerCallID) copy(dAtA[i:], m.CallerCallID) i = encodeVarintAsync(dAtA, i, uint64(len(m.CallerCallID))) i-- + dAtA[i] = 0x32 + } + if len(m.ParentAddr) > 0 { + i -= len(m.ParentAddr) + copy(dAtA[i:], m.ParentAddr) + i = encodeVarintAsync(dAtA, i, uint64(len(m.ParentAddr))) + i-- dAtA[i] = 0x2a } if len(m.CallerAddr) > 0 { @@ -1930,6 +1949,10 @@ func (m *SerializableAsyncContext) Size() (n int) { if l > 0 { n += 1 + l + sovAsync(uint64(l)) } + l = len(m.ParentAddr) + if l > 0 { + n += 1 + l + sovAsync(uint64(l)) + } l = len(m.CallerCallID) if l > 0 { n += 1 + l + sovAsync(uint64(l)) @@ -2094,6 +2117,7 @@ func (this *SerializableAsyncContext) String() string { `CallID:` + fmt.Sprintf("%v", this.CallID) + `,`, `CallType:` + fmt.Sprintf("%v", this.CallType) + `,`, `CallerAddr:` + fmt.Sprintf("%v", this.CallerAddr) + `,`, + `ParentAddr:` + fmt.Sprintf("%v", this.ParentAddr) + `,`, `CallerCallID:` + fmt.Sprintf("%v", this.CallerCallID) + `,`, `CallbackAsyncInitiatorCallID:` + fmt.Sprintf("%v", this.CallbackAsyncInitiatorCallID) + `,`, `Callback:` + fmt.Sprintf("%v", this.Callback) + `,`, @@ -3699,6 +3723,40 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ParentAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAsync + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAsync + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAsync + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ParentAddr = append(m.ParentAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ParentAddr == nil { + m.ParentAddr = []byte{} + } + iNdEx = postIndex + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CallerCallID", wireType) } @@ -3732,7 +3790,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { m.CallerCallID = []byte{} } iNdEx = postIndex - case 6: + case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CallbackAsyncInitiatorCallID", wireType) } @@ -3766,7 +3824,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { m.CallbackAsyncInitiatorCallID = []byte{} } iNdEx = postIndex - case 7: + case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Callback", wireType) } @@ -3798,7 +3856,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { } m.Callback = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 8: + case 9: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field CallbackData", wireType) } @@ -3832,7 +3890,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { m.CallbackData = []byte{} } iNdEx = postIndex - case 9: + case 10: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field GasAccumulated", wireType) } @@ -3851,7 +3909,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { break } } - case 10: + case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ReturnData", wireType) } @@ -3885,7 +3943,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { m.ReturnData = []byte{} } iNdEx = postIndex - case 11: + case 12: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AsyncCallGroups", wireType) } @@ -3919,7 +3977,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 12: + case 13: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field CallsCounter", wireType) } @@ -3938,7 +3996,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { break } } - case 13: + case 14: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TotalCallsCounter", wireType) } @@ -3957,7 +4015,7 @@ func (m *SerializableAsyncContext) Unmarshal(dAtA []byte) error { break } } - case 14: + case 15: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ChildResults", wireType) } diff --git a/vmhost/contexts/async.proto b/vmhost/contexts/async.proto index 55d83a20d..cf7e84ac8 100644 --- a/vmhost/contexts/async.proto +++ b/vmhost/contexts/async.proto @@ -67,14 +67,15 @@ message SerializableAsyncContext { bytes CallID = 2; SerializableCallType CallType = 3; bytes CallerAddr = 4; - bytes CallerCallID = 5; - bytes CallbackAsyncInitiatorCallID = 6; - string Callback = 7; - bytes CallbackData = 8; - uint64 GasAccumulated = 9; - bytes ReturnData = 10; - repeated vmhost.SerializableAsyncCallGroup asyncCallGroups = 11; - uint64 CallsCounter = 12; - uint64 TotalCallsCounter = 13; - SerializableVMOutput ChildResults = 14; + bytes ParentAddr = 5; + bytes CallerCallID = 6; + bytes CallbackAsyncInitiatorCallID = 7; + string Callback = 8; + bytes CallbackData = 9; + uint64 GasAccumulated = 10; + bytes ReturnData = 11; + repeated vmhost.SerializableAsyncCallGroup asyncCallGroups = 12; + uint64 CallsCounter = 13; + uint64 TotalCallsCounter = 14; + SerializableVMOutput ChildResults = 15; } diff --git a/vmhost/contexts/asyncComposability.go b/vmhost/contexts/asyncComposability.go index c7a859459..495aa30ff 100644 --- a/vmhost/contexts/asyncComposability.go +++ b/vmhost/contexts/asyncComposability.go @@ -12,6 +12,7 @@ func (context *asyncContext) NotifyChildIsComplete(callID []byte, gasToAccumulat logAsync.Trace("", "address", string(context.address)) logAsync.Trace("", "callID", context.callID) // DebugCallIDAsString logAsync.Trace("", "callerAddr", string(context.callerAddr)) + logAsync.Trace("", "parentAddr", string(context.parentAddr)) logAsync.Trace("", "callerCallID", context.callerCallID) logAsync.Trace("", "notifier callID", callID) logAsync.Trace("", "gasToAccumulate", gasToAccumulate) @@ -33,7 +34,7 @@ func (context *asyncContext) completeChild(callID []byte, gasToAccumulate uint64 return context.CompleteChildConditional(true, callID, gasToAccumulate) } -// CompleteChildConditional complets a child and accumulates the provided gas to the async context +// CompleteChildConditional completes a child and accumulates the provided gas to the async context func (context *asyncContext) CompleteChildConditional(isChildComplete bool, callID []byte, gasToAccumulate uint64) error { if !isChildComplete { return nil @@ -52,7 +53,7 @@ func (context *asyncContext) CompleteChildConditional(isChildComplete bool, call func (context *asyncContext) complete() error { // There are no more callbacks to return from other shards. The context can // be deleted from storage. - err := context.DeleteFromAddress(context.address) + err := context.DeleteFromCallID(context.callID) if err != nil { return err } diff --git a/vmhost/contexts/asyncLocal.go b/vmhost/contexts/asyncLocal.go index 15210eab5..9b59bf6fe 100644 --- a/vmhost/contexts/asyncLocal.go +++ b/vmhost/contexts/asyncLocal.go @@ -64,9 +64,9 @@ func (context *asyncContext) executeAsyncLocalCall(asyncCall *vmhost.AsyncCall) } if destinationCallInput.Function == vmhost.UpgradeFunctionName { - context.host.CompleteLogEntriesWithCallType(vmOutput, "UpgradeFromSource") + context.host.CompleteLogEntriesWithCallType(vmOutput, vmhost.UpgradeFromSourceString) } else { - context.host.CompleteLogEntriesWithCallType(vmOutput, "AsyncCall") + context.host.CompleteLogEntriesWithCallType(vmOutput, vmhost.AsyncCallString) } logAsync.Trace("executeAsyncLocalCall", @@ -87,7 +87,7 @@ func (context *asyncContext) executeAsyncLocalCall(asyncCall *vmhost.AsyncCall) return vmhost.ErrAsyncNoOutputFromCallback } - context.host.CompleteLogEntriesWithCallType(callbackVMOutput, "AsyncCallback") + context.host.CompleteLogEntriesWithCallType(callbackVMOutput, vmhost.AsyncCallbackString) if isCallbackComplete { callbackGasRemaining := callbackVMOutput.GasRemaining @@ -103,15 +103,15 @@ func (context *asyncContext) executeAsyncLocalCall(asyncCall *vmhost.AsyncCall) } // ExecuteSyncCallbackAndFinishOutput executes the callback and finishes the output -//TODO rename to executeLocalCallbackAndFinishOutput +// TODO rename to executeLocalCallbackAndFinishOutput func (context *asyncContext) ExecuteSyncCallbackAndFinishOutput( asyncCall *vmhost.AsyncCall, vmOutput *vmcommon.VMOutput, _ *vmcommon.ContractCallInput, gasAccumulated uint64, err error) (bool, *vmcommon.VMOutput) { - callbackVMOutput, isComplete, callbackErr := context.executeSyncCallback(asyncCall, vmOutput, gasAccumulated, err) - context.finishAsyncLocalCallbackExecution(callbackVMOutput, callbackErr, vmOutput.ReturnCode) + callbackVMOutput, isComplete, _ := context.executeSyncCallback(asyncCall, vmOutput, gasAccumulated, err) + context.finishAsyncLocalCallbackExecution() return isComplete, callbackVMOutput } @@ -183,8 +183,8 @@ func (context *asyncContext) executeSyncHalfOfBuiltinFunction(asyncCall *vmhost. if vmOutput.ReturnCode != vmcommon.Ok { asyncCall.Reject() if asyncCall.HasCallback() { - callbackVMOutput, _, callbackErr := context.executeSyncCallback(asyncCall, vmOutput, 0, err) - context.finishAsyncLocalCallbackExecution(callbackVMOutput, callbackErr, 0) + _, _, _ = context.executeSyncCallback(asyncCall, vmOutput, 0, err) + context.finishAsyncLocalCallbackExecution() } } @@ -195,33 +195,9 @@ func (context *asyncContext) executeSyncHalfOfBuiltinFunction(asyncCall *vmhost. return nil } -// TODO(fix) this function -//nolint:all -func (context *asyncContext) finishAsyncLocalCallbackExecution( - vmOutput *vmcommon.VMOutput, - err error, - destinationReturnCode vmcommon.ReturnCode, -) { - +func (context *asyncContext) finishAsyncLocalCallbackExecution() { runtime := context.host.Runtime() - runtime.GetVMInput().GasProvided = 0 - - // if vmOutput == nil { - // vmOutput = output.CreateVMOutputInCaseOfError(err) - // } - - // if setReturnCode { - // if vmOutput.ReturnCode != vmcommon.Ok { - // output.SetReturnCode(vmOutput.ReturnCode) - // } else { - // output.SetReturnCode(destinationReturnCode) - // } - // } - - // output.SetReturnMessage(vmOutput.ReturnMessage) - // output.Finish([]byte(vmOutput.ReturnCode.String())) - // output.Finish(runtime.GetCurrentTxHash()) } func (context *asyncContext) createContractCallInput(asyncCall *vmhost.AsyncCall) (*vmcommon.ContractCallInput, error) { @@ -273,7 +249,10 @@ func (context *asyncContext) createCallbackInput( ) (*vmcommon.ContractCallInput, error) { runtime := context.host.Runtime() - actualCallbackInitiator := context.determineDestinationForAsyncCall(asyncCall.GetDestination(), asyncCall.GetData()) + actualCallbackInitiator, err := context.determineDestinationForAsyncCall(asyncCall.GetDestination(), asyncCall.GetData()) + if err != nil { + return nil, err + } arguments := context.getArgumentsForCallback(vmOutput, destinationErr) diff --git a/vmhost/contexts/asyncPersistence.go b/vmhost/contexts/asyncPersistence.go index 20ea85da3..cd9eba2f8 100644 --- a/vmhost/contexts/asyncPersistence.go +++ b/vmhost/contexts/asyncPersistence.go @@ -2,7 +2,6 @@ package contexts import ( "errors" - "github.com/multiversx/mx-chain-core-go/data/vm" "github.com/multiversx/mx-chain-core-go/marshal" vmcommon "github.com/multiversx/mx-chain-vm-common-go" @@ -46,11 +45,11 @@ func (context *asyncContext) LoadParentContext() error { } } -// DeleteFromAddress deletes the persisted state of the AsyncContext from the contract storage. -func (context *asyncContext) DeleteFromAddress(address []byte) error { +// DeleteFromCallID deletes the persisted state of the AsyncContext from the contract storage. +func (context *asyncContext) DeleteFromCallID(callID []byte) error { storage := context.host.Storage() - storageKey := getAsyncContextStorageKey(context.asyncStorageDataPrefix, context.callID) - _, err := storage.SetProtectedStorageToAddressUnmetered(address, storageKey, nil) + storageKey := getAsyncContextStorageKey(context.asyncStorageDataPrefix, callID) + _, err := storage.SetProtectedStorageToAddressUnmetered(context.address, storageKey, nil) return err } @@ -85,6 +84,7 @@ func (context *asyncContext) loadSpecificContext(address []byte, callID []byte) context.address = loadedContext.address context.callID = loadedContext.callID context.callerAddr = loadedContext.callerAddr + context.parentAddr = loadedContext.parentAddr context.callerCallID = loadedContext.callerCallID context.callbackAsyncInitiatorCallID = loadedContext.callbackAsyncInitiatorCallID context.callType = loadedContext.callType @@ -129,6 +129,7 @@ func (context *asyncContext) toSerializable() *SerializableAsyncContext { CallID: context.callID, CallType: SerializableCallType(context.callType), CallerAddr: context.callerAddr, + ParentAddr: context.parentAddr, CallerCallID: context.callerCallID, CallbackAsyncInitiatorCallID: context.callbackAsyncInitiatorCallID, Callback: context.callback, @@ -151,6 +152,7 @@ func fromSerializable(serializedContext *SerializableAsyncContext) *asyncContext callsCounter: serializedContext.CallsCounter, totalCallsCounter: serializedContext.TotalCallsCounter, callerAddr: serializedContext.CallerAddr, + parentAddr: serializedContext.ParentAddr, callerCallID: serializedContext.CallerCallID, callType: vm.CallType(serializedContext.CallType), callbackAsyncInitiatorCallID: serializedContext.CallbackAsyncInitiatorCallID, diff --git a/vmhost/contexts/async_test.go b/vmhost/contexts/async_test.go index 40433b24a..d91fb22ba 100644 --- a/vmhost/contexts/async_test.go +++ b/vmhost/contexts/async_test.go @@ -431,16 +431,7 @@ func TestAsyncContext_UpdateCurrentCallStatus(t *testing.T) { vmInput.Arguments = [][]byte{{0}} host.Runtime().InitStateFromContractCallInput(vmInput) asyncCall, isLegacy, err = async.UpdateCurrentAsyncCallStatus(contract, []byte{}, &vmInput.VMInput) - require.Equal(t, asyncCall, &vmhost.AsyncCall{ - Status: vmhost.AsyncCallResolved, - Destination: contract, - SuccessCallback: vmhost.CallbackFunctionName, - ErrorCallback: vmhost.CallbackFunctionName, - GasLimit: vmInput.GasProvided, - GasLocked: vmInput.GasLocked, - }) - require.True(t, isLegacy) - require.Nil(t, err) + require.NotNil(t, err) // CallType == AsynchronousCallback, and there is an AsyncCall registered, // but it's not the expected one. @@ -457,16 +448,7 @@ func TestAsyncContext_UpdateCurrentCallStatus(t *testing.T) { vmInput.Arguments = [][]byte{{0}} host.Runtime().InitStateFromContractCallInput(vmInput) asyncCall, isLegacy, err = async.UpdateCurrentAsyncCallStatus(contract, []byte("callID_2"), &vmInput.VMInput) - require.Equal(t, asyncCall, &vmhost.AsyncCall{ - Status: vmhost.AsyncCallResolved, - Destination: contract, - SuccessCallback: vmhost.CallbackFunctionName, - ErrorCallback: vmhost.CallbackFunctionName, - GasLimit: vmInput.GasProvided, - GasLocked: vmInput.GasLocked, - }) - require.True(t, isLegacy) - require.Nil(t, err) + require.NotNil(t, err) // CallType == AsynchronousCallback, but this time there is a corresponding AsyncCall // registered, causing async.UpdateCurrentCallStatus() to find and update the AsyncCall @@ -835,7 +817,7 @@ func createCallbackInput(t *testing.T, lastTransfer *vmcommon.OutputTransfer) (* return createCallbackInputWithVMOutput(t, vmOutput, lastTransfer) } -func createCallbackInputWithVMOutput(t *testing.T, vmOutput *vmcommon.VMOutput, lastTransfer *vmcommon.OutputTransfer) (*vmcommon.ContractCallInput, *vmcommon.ContractCallInput, uint64) { +func createCallbackInputWithVMOutput(t *testing.T, vmOutput *vmcommon.VMOutput, _ *vmcommon.OutputTransfer) (*vmcommon.ContractCallInput, *vmcommon.ContractCallInput, uint64) { host, _, originalVMInput := initializeVMAndWasmerAsyncContextWithAliceAndBobWithBuiltIn(t, true) host.Runtime().InitStateFromContractCallInput(originalVMInput) async := makeAsyncContext(t, host, Alice) @@ -909,7 +891,7 @@ func TestAsyncContext_FinishSyncExecution_NilError_NilVMOutput(t *testing.T) { host, _, originalVMInput := initializeVMAndWasmerAsyncContextWithAliceAndBob(t) host.Runtime().InitStateFromContractCallInput(originalVMInput) async := makeAsyncContext(t, host, nil) - async.finishAsyncLocalCallbackExecution(nil, nil, 0) + async.finishAsyncLocalCallbackExecution() // The expectedOutput must also contain an OutputAccount corresponding to // Alice, because of a call to host.Output().GetOutputAccount() in @@ -928,8 +910,7 @@ func TestAsyncContext_FinishSyncExecution_Error_NilVMOutput(t *testing.T) { host.Runtime().InitStateFromContractCallInput(originalVMInput) async := makeAsyncContext(t, host, nil) - syncExecErr := vmhost.ErrNotEnoughGas - async.finishAsyncLocalCallbackExecution(nil, syncExecErr, 0) + async.finishAsyncLocalCallbackExecution() expectedOutput := vmhost.MakeEmptyVMOutput() expectedOutput.GasRemaining = host.Metering().GasLeft() @@ -956,8 +937,7 @@ func TestAsyncContext_FinishSyncExecution_ErrorAndVMOutput(t *testing.T) { syncExecOutput := vmhost.MakeEmptyVMOutput() syncExecOutput.ReturnCode = vmcommon.UserError syncExecOutput.ReturnMessage = "user made an error" - syncExecErr := vmhost.ErrSignalError - async.finishAsyncLocalCallbackExecution(syncExecOutput, syncExecErr, 0) + async.finishAsyncLocalCallbackExecution() expectedOutput := vmhost.MakeEmptyVMOutput() expectedOutput.GasRemaining = host.Metering().GasLeft() diff --git a/vmhost/contexts/managedType.go b/vmhost/contexts/managedType.go index 24fa4fa8a..b26ebe089 100644 --- a/vmhost/contexts/managedType.go +++ b/vmhost/contexts/managedType.go @@ -5,6 +5,7 @@ import ( "crypto/elliptic" "encoding/binary" "errors" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" "io" basicMath "math" "math/big" @@ -58,12 +59,19 @@ type managedTypesContext struct { randomnessGenerator math.RandomnessGenerator } +// structure for transfers where scA call scB and scB makes transfers without execution to scA +type backTransfers struct { + ESDTTransfers []*vmcommon.ESDTTransfer + CallValue *big.Int +} + type managedTypesState struct { bigIntValues bigIntMap bigFloatValues bigFloatMap ecValues ellipticCurveMap mBufferValues managedBufferMap mMapValues managedMapMap + backTransfers backTransfers } // NewManagedTypesContext creates a new managedTypesContext @@ -80,6 +88,10 @@ func NewManagedTypesContext(host vmhost.VMHost) (*managedTypesContext, error) { ecValues: make(ellipticCurveMap), mBufferValues: make(managedBufferMap), mMapValues: make(managedMapMap), + backTransfers: backTransfers{ + ESDTTransfers: make([]*vmcommon.ESDTTransfer, 0), + CallValue: big.NewInt(0), + }, }, managedTypesStack: make([]managedTypesState, 0), randomnessGenerator: nil, @@ -116,18 +128,25 @@ func (context *managedTypesContext) InitState() { bigFloatValues: make(bigFloatMap), ecValues: make(ellipticCurveMap), mBufferValues: make(managedBufferMap), - mMapValues: make(managedMapMap)} + mMapValues: make(managedMapMap), + backTransfers: backTransfers{ + ESDTTransfers: make([]*vmcommon.ESDTTransfer, 0), + CallValue: big.NewInt(0), + }, + } } // PushState appends the values map to the state stack func (context *managedTypesContext) PushState() { newBigIntState, newBigFloatState, newEcState, newmBufferState, newmMapState := context.clone() + newTransfers := context.cloneBackTransfers() context.managedTypesStack = append(context.managedTypesStack, managedTypesState{ bigIntValues: newBigIntState, bigFloatValues: newBigFloatState, ecValues: newEcState, mBufferValues: newmBufferState, mMapValues: newmMapState, + backTransfers: newTransfers, }) } @@ -144,11 +163,15 @@ func (context *managedTypesContext) PopSetActiveState() { prevEcValues := prevState.ecValues prevmBufferValues := prevState.mBufferValues prevmMapValues := prevState.mMapValues + prevBackTransfers := prevState.backTransfers + context.managedTypesValues.bigIntValues = prevBigIntValues context.managedTypesValues.bigFloatValues = prevBigFloatValues context.managedTypesValues.ecValues = prevEcValues context.managedTypesValues.mBufferValues = prevmBufferValues context.managedTypesValues.mMapValues = prevmMapValues + context.managedTypesValues.backTransfers = prevBackTransfers + context.managedTypesStack = context.managedTypesStack[:managedTypesStackLen-1] } @@ -761,3 +784,44 @@ func (context *managedTypesContext) getKeyValueFromManagedMap(mMapHandle int32, return mMap, key, value, foundValue, nil } + +// AddBackTransfers add transfers to back transfers structure +func (context *managedTypesContext) AddBackTransfers(transfers []*vmcommon.ESDTTransfer) { + context.managedTypesValues.backTransfers.ESDTTransfers = append(context.managedTypesValues.backTransfers.ESDTTransfers, transfers...) +} + +// AddValueOnlyBackTransfer add to back transfer value +func (context *managedTypesContext) AddValueOnlyBackTransfer(value *big.Int) { + context.managedTypesValues.backTransfers.CallValue.Add(context.managedTypesValues.backTransfers.CallValue, value) +} + +// GetBackTransfers returns all ESDT transfers and accumulated value as well, will clean accumulated values +func (context *managedTypesContext) GetBackTransfers() ([]*vmcommon.ESDTTransfer, *big.Int) { + clonedTransfers := context.cloneBackTransfers() + context.managedTypesValues.backTransfers = backTransfers{ + ESDTTransfers: make([]*vmcommon.ESDTTransfer, 0), + CallValue: big.NewInt(0), + } + + return clonedTransfers.ESDTTransfers, clonedTransfers.CallValue +} + +func (context *managedTypesContext) cloneBackTransfers() backTransfers { + currentBackTransfers := context.managedTypesValues.backTransfers + + newBackTransfers := backTransfers{ + ESDTTransfers: make([]*vmcommon.ESDTTransfer, len(currentBackTransfers.ESDTTransfers)), + CallValue: big.NewInt(0).Set(currentBackTransfers.CallValue), + } + + for index, transfer := range currentBackTransfers.ESDTTransfers { + newBackTransfers.ESDTTransfers[index] = &vmcommon.ESDTTransfer{ + ESDTValue: big.NewInt(0).Set(transfer.ESDTValue), + ESDTTokenName: transfer.ESDTTokenName, + ESDTTokenType: transfer.ESDTTokenType, + ESDTTokenNonce: transfer.ESDTTokenNonce, + } + } + + return newBackTransfers +} diff --git a/vmhost/contexts/output.go b/vmhost/contexts/output.go index 92365f3bb..1c7e93207 100644 --- a/vmhost/contexts/output.go +++ b/vmhost/contexts/output.go @@ -1,7 +1,7 @@ package contexts import ( - "encoding/hex" + "bytes" "errors" "math/big" @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/vm" logger "github.com/multiversx/mx-chain-logger-go" vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/parsers" "github.com/multiversx/mx-chain-vm-go/executor" "github.com/multiversx/mx-chain-vm-go/math" "github.com/multiversx/mx-chain-vm-go/vmhost" @@ -25,6 +26,7 @@ type outputContext struct { stateStack []*vmcommon.VMOutput codeUpdates map[string]struct{} crtTransferIndex uint32 + callArgsParser vmcommon.CallArgsParser } // NewOutputContext creates a new outputContext @@ -37,6 +39,7 @@ func NewOutputContext(host vmhost.VMHost) (*outputContext, error) { host: host, stateStack: make([]*vmcommon.VMOutput, 0), crtTransferIndex: 1, + callArgsParser: parsers.NewCallArgsParser(), } context.InitState() @@ -319,23 +322,51 @@ func (context *outputContext) TransferValueOnly(destination []byte, sender []byt } } + return nil +} + +func (context *outputContext) isBackTransferWithoutExecution(sender, destination []byte, input []byte) bool { + if len(input) != 0 { + return false + } + if !core.IsSmartContractAddress(destination) { + return false + } + vmInput := context.host.Runtime().GetVMInput() - context.WriteLogWithIdentifier( - sender, - [][]byte{value.Bytes(), destination}, - vmcommon.FormatLogDataForCall("", vmInput.Function, vmInput.Arguments), - []byte("transferValueOnly"), - ) - return nil + currentExecutionCallerAddress := vmInput.CallerAddr + currentExecutionDestinationAddress := vmInput.RecipientAddr + + if vmInput.CallType == vm.AsynchronousCallBack { + currentExecutionCallerAddress = context.host.Async().GetParentAddress() + } + + if !bytes.Equal(currentExecutionCallerAddress, destination) || + !bytes.Equal(currentExecutionDestinationAddress, sender) { + return false + } + + return true } // Transfer handles any necessary value transfer required and takes // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. -func (context *outputContext) Transfer(destination []byte, sender []byte, gasLimit uint64, gasLocked uint64, value *big.Int, asyncData []byte, input []byte, callType vm.CallType) error { +func (context *outputContext) Transfer( + destination []byte, + sender []byte, + gasLimit uint64, + gasLocked uint64, + value *big.Int, + asyncData []byte, + input []byte, + callType vm.CallType, +) error { checkPayableIfNotCallback := gasLimit > 0 && callType != vm.AsynchronousCallBack - err := context.TransferValueOnly(destination, sender, value, checkPayableIfNotCallback) + isBackTransfer := context.isBackTransferWithoutExecution(sender, destination, input) + checkPayable := checkPayableIfNotCallback || !isBackTransfer + err := context.TransferValueOnly(destination, sender, value, checkPayable) if err != nil { return err } @@ -358,9 +389,52 @@ func (context *outputContext) Transfer(destination []byte, sender []byte, gasLim AppendOutputTransfers(destAcc, destAcc.OutputTransfers, outputTransfer) logOutput.Trace("transfer value added") + + function, args, errNotCritical := context.callArgsParser.ParseData(string(input)) + + isSimpleTransfer := errNotCritical != nil || !core.IsSmartContractAddress(destination) || gasLimit == 0 + if !isBackTransfer && isSimpleTransfer { + context.WriteLogWithIdentifier( + sender, + [][]byte{value.Bytes(), destination}, + [][]byte{[]byte(vmhost.DirectCallString), input}, + []byte(vmhost.TransferValueOnlyString), + ) + return nil + } + + executionType := callType + if executionType == vm.DirectCall { + executionType = vm.ESDTTransferAndExecute + } + + context.WriteLogWithIdentifier( + sender, + [][]byte{value.Bytes(), destination}, + vmcommon.FormatLogDataForCall(getExecutionTypeString(executionType, isBackTransfer), function, args), + []byte(vmhost.TransferValueOnlyString), + ) + return nil } +func getExecutionTypeString(callType vm.CallType, isBackTransfer bool) string { + if isBackTransfer { + return vmhost.BackTransferString + } + + switch callType { + case vm.ESDTTransferAndExecute: + return vmhost.TransferAndExecuteString + case vm.AsynchronousCall: + return vmhost.AsyncCallString + case vm.AsynchronousCallBack: + return vmhost.AsyncCallbackString + } + + return vmhost.DirectCallString +} + // TransferESDT makes the esdt/nft transfer and exports the data if it is cross shard func (context *outputContext) TransferESDT( transfersArgs *vmhost.ESDTTransfersArgs, @@ -374,11 +448,19 @@ func (context *outputContext) TransferESDT( sameShard := context.host.AreInSameShard(transfersArgs.Sender, transfersArgs.Destination) callType := vm.DirectCall isExecution := isSmartContract && callInput != nil - if isExecution { - callType = vm.ESDTTransferAndExecute + isBackTransfer := !isExecution && context.isBackTransferWithoutExecution(transfersArgs.Sender, transfersArgs.Destination, nil) + + if callInput != nil { + callType = callInput.CallType + transfersArgs.Function = callInput.Function + transfersArgs.Arguments = callInput.Arguments + } + executionType := callType + if callType == vm.DirectCall && (isExecution || isBackTransfer) { + executionType = vm.ESDTTransferAndExecute } - vmOutput, gasConsumedByTransfer, err := context.host.ExecuteESDTTransfer(transfersArgs, callType) + vmOutput, gasConsumedByTransfer, err := context.host.ExecuteESDTTransfer(transfersArgs, executionType) if err != nil { return 0, err } @@ -405,33 +487,22 @@ func (context *outputContext) TransferESDT( } destAcc, _ := context.GetOutputAccount(transfersArgs.Destination) - outputTransfer := vmcommon.OutputTransfer{ - Index: context.NextOutputTransferIndex(), - Value: big.NewInt(0), - GasLimit: gasRemaining, - GasLocked: 0, - Data: []byte{}, - CallType: vm.DirectCall, - SenderAddress: transfersArgs.Sender, - } - - outputTransfer.Data = context.getOutputTransferDataFromESDTTransfer(transfersArgs.Transfers, vmOutput, sameShard, transfersArgs.Destination) - - if sameShard { - outputTransfer.GasLimit = 0 - } - - if callInput != nil { - scCallData := "@" + hex.EncodeToString([]byte(callInput.Function)) - for _, arg := range callInput.Arguments { - scCallData += "@" + hex.EncodeToString(arg) + outputAcc, ok := vmOutput.OutputAccounts[string(transfersArgs.Destination)] + + if ok && len(outputAcc.OutputTransfers) == 1 { + esdtOutTransfer := outputAcc.OutputTransfers[0] + esdtOutTransfer.GasLimit = gasRemaining + esdtOutTransfer.CallType = callType + if sameShard { + esdtOutTransfer.GasLimit = 0 } - outputTransfer.Data = append(outputTransfer.Data, []byte(scCallData)...) - } - AppendOutputTransfers(destAcc, destAcc.OutputTransfers, outputTransfer) + AppendOutputTransfers(destAcc, destAcc.OutputTransfers, esdtOutTransfer) + } + context.host.CompleteLogEntriesWithCallType(vmOutput, getExecutionTypeString(executionType, isBackTransfer)) context.outputState.Logs = append(context.outputState.Logs, vmOutput.Logs...) + return gasRemaining, nil } @@ -443,41 +514,6 @@ func AppendOutputTransfers(account *vmcommon.OutputAccount, existingTransfers [] } } -func (context *outputContext) getOutputTransferDataFromESDTTransfer( - transfers []*vmcommon.ESDTTransfer, - vmOutput *vmcommon.VMOutput, - sameShard bool, - destination []byte, -) []byte { - - if len(transfers) == 1 && transfers[0].ESDTTokenNonce == 0 { - return []byte(core.BuiltInFunctionESDTTransfer + "@" + hex.EncodeToString(transfers[0].ESDTTokenName) + "@" + hex.EncodeToString(transfers[0].ESDTValue.Bytes())) - } - - if !sameShard { - outTransfer, ok := vmOutput.OutputAccounts[string(destination)] - if ok && len(outTransfer.OutputTransfers) == 1 { - return outTransfer.OutputTransfers[0].Data - } - } - - if len(transfers) == 1 { - data := []byte(core.BuiltInFunctionESDTNFTTransfer + "@" + - hex.EncodeToString(transfers[0].ESDTTokenName) + "@" + - hex.EncodeToString(big.NewInt(0).SetUint64(transfers[0].ESDTTokenNonce).Bytes()) + "@" + - hex.EncodeToString(transfers[0].ESDTValue.Bytes()) + "@" + - hex.EncodeToString(destination)) - return data - } - - data := core.BuiltInFunctionMultiESDTNFTTransfer + "@" + hex.EncodeToString(destination) + "@" + hex.EncodeToString(big.NewInt(int64(len(transfers))).Bytes()) - for _, transfer := range transfers { - data += "@" + hex.EncodeToString(transfer.ESDTTokenName) + "@" + hex.EncodeToString(big.NewInt(0).SetUint64(transfer.ESDTTokenNonce).Bytes()) + "@" + hex.EncodeToString(transfer.ESDTValue.Bytes()) - } - - return []byte(data) -} - func (context *outputContext) hasSufficientBalance(address []byte, value *big.Int) bool { senderBalance := context.host.Blockchain().GetBalanceBigInt(address) return senderBalance.Cmp(value) >= 0 @@ -647,7 +683,7 @@ func (context *outputContext) GetCrtTransferIndex() uint32 { return context.crtTransferIndex } -// SetOutputTransferIndex sets the current output transfer index +// SetCrtTransferIndex sets the current output transfer index func (context *outputContext) SetCrtTransferIndex(index uint32) { context.crtTransferIndex = index } diff --git a/vmhost/contexts/storage.go b/vmhost/contexts/storage.go index 611aee723..dd8483d0a 100644 --- a/vmhost/contexts/storage.go +++ b/vmhost/contexts/storage.go @@ -168,10 +168,16 @@ func (context *storageContext) GetStorageFromAddress(address []byte, key []byte) } } - return context.GetStorageFromAddressNoChecks(address, key) + value, trieDepth, usedCache, err := context.getStorageFromAddressUnmetered(address, key) + + context.useExtraGasForKeyIfNeeded(key, usedCache) + context.useGasForValueIfNeeded(value, usedCache) + + logStorage.Trace("get from address", "address", address, "key", key, "value", value) + return value, trieDepth, usedCache, err } -// GetStorageFromAddressNoChecks same as GetStorageFromAddress but used internaly by vm, so no permissions checks are necessary +// GetStorageFromAddressNoChecks same as GetStorageFromAddress but used internally by vm, so no permissions checks are necessary func (context *storageContext) GetStorageFromAddressNoChecks(address []byte, key []byte) ([]byte, uint32, bool, error) { // If the requested key is protected by the node, the stored value // could have been changed by a built-in function in the meantime, even if @@ -180,9 +186,6 @@ func (context *storageContext) GetStorageFromAddressNoChecks(address []byte, key // StorageUpdates. value, trieDepth, usedCache, err := context.getStorageFromAddressUnmetered(address, key) - context.useExtraGasForKeyIfNeeded(key, usedCache) - context.useGasForValueIfNeeded(value, usedCache) - logStorage.Trace("get from address", "address", address, "key", key, "value", value) return value, trieDepth, usedCache, err } @@ -256,14 +259,14 @@ func (context *storageContext) SetStorage(key []byte, value []byte) (vmhost.Stor return context.setStorageToAddress(context.address, key, value) } -// SetProtectedStorageToAddress sets the given value at the given key, for the specified address. This is only used internaly by vm! +// SetProtectedStorageToAddress sets the given value at the given key, for the specified address. This is only used internally by vm! func (context *storageContext) SetProtectedStorageToAddress(address []byte, key []byte, value []byte) (vmhost.StorageStatus, error) { context.disableStorageProtection() defer context.enableStorageProtection() return context.setStorageToAddress(address, key, value) } -// SetProtectedStorageToAddressUnmetered sets the given value at the given key, for the specified address. This is only used internaly by vm! +// SetProtectedStorageToAddressUnmetered sets the given value at the given key, for the specified address. This is only used internally by vm! // No gas cost involved, e.g. called by async.Save() func (context *storageContext) SetProtectedStorageToAddressUnmetered(address []byte, key []byte, value []byte) (vmhost.StorageStatus, error) { context.disableStorageProtection() diff --git a/vmhost/errors.go b/vmhost/errors.go index 98e01c1a8..75ad7beae 100644 --- a/vmhost/errors.go +++ b/vmhost/errors.go @@ -118,7 +118,7 @@ var ErrStorageValueOutOfRange = errors.New("storage value out of range") // ErrDivZero signals that an attempt to divide by 0 has been made var ErrDivZero = errors.New("division by 0") -// ErrBitwiseNegative signals that an attempt to apply a bitwise operation on negative numbers has been made +// ErrBigIntCannotBeRepresentedAsInt64 signals that an attempt to apply a bitwise operation on negative numbers has been made var ErrBigIntCannotBeRepresentedAsInt64 = errors.New("big int cannot be represented as int64") // ErrBitwiseNegative signals that an attempt to apply a bitwise operation on negative numbers has been made @@ -292,3 +292,6 @@ var ErrCannotWriteOnReadOnly = errors.New("cannot write on read only mode") // ErrEmptyProtectedKeyPrefix signals that the protected key prefix is empty or nil var ErrEmptyProtectedKeyPrefix = errors.New("protectedKeyPrefix is empty or nil") + +// ErrInvalidGasProvided signals that an unacceptable GasProvided value was specified +var ErrInvalidGasProvided = errors.New("invalid gas provided") diff --git a/vmhost/hostCore/execution.go b/vmhost/hostCore/execution.go index decd02fcd..87de917f4 100644 --- a/vmhost/hostCore/execution.go +++ b/vmhost/hostCore/execution.go @@ -95,12 +95,6 @@ func (host *vmHost) performCodeDeployment(input vmhost.CodeDeployInput, initFunc return nil, vmhost.ErrContractInvalid } - defer func() { - if !contexts.WarmInstancesEnabled { - runtime.CleanInstance() - } - }() - err = initFunction() if err != nil { return nil, err @@ -257,12 +251,6 @@ func (host *vmHost) doRunSmartContractCall(input *vmcommon.ContractCallInput) *v return vmOutput } - defer func() { - if !contexts.WarmInstancesEnabled { - runtime.CleanInstance() - } - }() - err = host.callSCMethod() if err != nil { log.Trace("doRunSmartContractCall", "error", err) @@ -274,7 +262,7 @@ func (host *vmHost) doRunSmartContractCall(input *vmcommon.ContractCallInput) *v output.RemoveNonUpdatedStorage() } vmOutput = output.GetVMOutput() - host.CompleteLogEntriesWithCallType(vmOutput, "DirectCall") + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.DirectCallString) log.Trace("doRunSmartContractCall finished", "retCode", vmOutput.ReturnCode, @@ -340,6 +328,7 @@ func (host *vmHost) ExecuteOnDestContext(input *vmcommon.ContractCallInput) (vmO isChildComplete = true if scExecutionInput != nil { vmOutput, isChildComplete, err = host.executeOnDestContextNoBuiltinFunction(scExecutionInput) + host.addNewBackTransfersFromVMOutput(vmOutput, scExecutionInput.CallerAddr, scExecutionInput.RecipientAddr) } if err != nil { @@ -351,14 +340,64 @@ func (host *vmHost) ExecuteOnDestContext(input *vmcommon.ContractCallInput) (vmO return } +func (host *vmHost) isESDTTransferWithoutExecution(transferData []byte, parent, child []byte) (*vmcommon.ParsedESDTTransfers, bool) { + function, args, err := host.callArgsParser.ParseData(string(transferData)) + if err != nil { + return nil, false + } + + esdtTransfers, err := host.esdtTransferParser.ParseESDTTransfers(child, parent, function, args) + if err != nil { + return nil, false + } + if esdtTransfers.CallFunction != "" { + return nil, false + } + + return esdtTransfers, true +} + +func (host *vmHost) addNewBackTransfersFromVMOutput(vmOutput *vmcommon.VMOutput, parent, child []byte) { + if vmOutput == nil || vmOutput.ReturnCode != vmcommon.Ok { + return + } + callerOutAcc, ok := vmOutput.OutputAccounts[string(parent)] + if !ok { + return + } + + for _, transfer := range callerOutAcc.OutputTransfers { + if !bytes.Equal(transfer.SenderAddress, child) { + continue + } + if transfer.CallType == vm.AsynchronousCallBack { + continue + } + + if transfer.Value.Cmp(vmhost.Zero) > 0 { + if len(transfer.Data) == 0 { + host.managedTypesContext.AddValueOnlyBackTransfer(transfer.Value) + } + continue + } + + esdtTransfers, isWithoutExec := host.isESDTTransferWithoutExecution(transfer.Data, parent, child) + if !isWithoutExec { + continue + } + + host.managedTypesContext.AddBackTransfers(esdtTransfers.ESDTTransfers) + } +} + func (host *vmHost) completeLogEntriesAfterBuiltinCall(input *vmcommon.ContractCallInput, vmOutput *vmcommon.VMOutput) { switch input.CallType { case vm.AsynchronousCall: - host.CompleteLogEntriesWithCallType(vmOutput, "AsyncCall") + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.AsyncCallString) case vm.AsynchronousCallBack: - host.CompleteLogEntriesWithCallType(vmOutput, "AyncCallback") + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.AsyncCallbackString) default: - host.CompleteLogEntriesWithCallType(vmOutput, "ExecuteOnDestContext") + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.ExecuteOnDestContextString) } } @@ -447,6 +486,14 @@ func (host *vmHost) executeOnDestContextNoBuiltinFunction(input *vmcommon.Contra return vmOutput, true, err } } + if len(input.ESDTTransfers) == 0 { + output.WriteLogWithIdentifier( + input.CallerAddr, + [][]byte{input.CallValue.Bytes(), input.RecipientAddr}, + vmcommon.FormatLogDataForCall("", input.Function, input.Arguments), + []byte(vmhost.TransferValueOnlyString), + ) + } err = host.execute(input) if err != nil { @@ -474,7 +521,7 @@ func (host *vmHost) finishExecuteOnDestContext(executeErr error) *vmcommon.VMOut } async.SetResults(vmOutput) - if !async.IsComplete() { + if !async.IsComplete() || async.HasLegacyGroup() { saveErr := async.Save() if saveErr != nil { vmOutput = output.CreateVMOutputInCaseOfError(saveErr) @@ -559,6 +606,12 @@ func (host *vmHost) ExecuteOnSameContext(input *vmcommon.ContractCallInput) erro runtime.AddError(err, input.Function) return err } + output.WriteLogWithIdentifier( + input.CallerAddr, + [][]byte{input.CallValue.Bytes(), input.RecipientAddr}, + vmcommon.FormatLogDataForCall(vmhost.ExecuteOnSameContextString, input.Function, input.Arguments), + []byte(vmhost.TransferValueOnlyString), + ) err = host.execute(input) runtime.AddError(err, input.Function) @@ -583,8 +636,6 @@ func (host *vmHost) finishExecuteOnSameContext(executeErr error) { // GasUsed for all accounts. vmOutput := output.GetVMOutput() - host.CompleteLogEntriesWithCallType(vmOutput, "ExecuteOnSameContext") - metering.PopMergeActiveState() output.PopDiscard() blockchain.PopDiscard() @@ -695,9 +746,9 @@ func (host *vmHost) CreateNewContract(input *vmcommon.ContractCreateInput, creat } if createContractCallType == vmhooks.DeployContract { - host.CompleteLogEntriesWithCallType(initVmOutput, "DeployFromSource") + host.CompleteLogEntriesWithCallType(initVmOutput, vmhost.DeployFromSourceString) } else { - host.CompleteLogEntriesWithCallType(initVmOutput, "CreateSmartContract") + host.CompleteLogEntriesWithCallType(initVmOutput, vmhost.DeploySmartContractString) } err = host.Async().CompleteChildConditional(isChildComplete, nil, 0) @@ -918,6 +969,13 @@ func (host *vmHost) ExecuteESDTTransfer(transfersArgs *vmhost.ESDTTransfersArgs, } } + if len(transfersArgs.Function) > 0 { + esdtTransferInput.Arguments = append(esdtTransferInput.Arguments, []byte(transfersArgs.Function)) + } + if len(transfersArgs.Arguments) > 0 { + esdtTransferInput.Arguments = append(esdtTransferInput.Arguments, transfersArgs.Arguments...) + } + vmOutput, err := host.Blockchain().ProcessBuiltInFunction(esdtTransferInput) log.Trace("ESDT transfer", "sender", transfersArgs.Sender, "dest", transfersArgs.Destination) for _, transfer := range transfers { @@ -937,6 +995,8 @@ func (host *vmHost) ExecuteESDTTransfer(transfersArgs *vmhost.ESDTTransfersArgs, return nil, 0, err } + host.addESDTTransferToVMOutputSCIntraShardCall(esdtTransferInput, vmOutput) + gasConsumed := math.SubUint64(esdtTransferInput.GasProvided, vmOutput.GasRemaining) for _, outAcc := range vmOutput.OutputAccounts { for _, transfer := range outAcc.OutputTransfers { @@ -1150,8 +1210,7 @@ func (host *vmHost) callSCMethodAsynchronousCallBack() error { runtime.GetContextAddress(), callerCallID, &runtime.GetVMInput().VMInput) - if err != nil && !isLegacy { - log.Trace("UpdateCurrentCallStatus failed", "error", err) + if err != nil { return err } @@ -1183,7 +1242,7 @@ func (host *vmHost) callSCMethodAsynchronousCallBack() error { } if isLegacy { - return nil + return async.DeleteFromCallID(async.GetCallbackAsyncInitiatorCallID()) } err = async.LoadParentContext() @@ -1226,19 +1285,15 @@ func (host *vmHost) callFunctionAndExecuteAsync() (bool, error) { return true, err } - isLegacy := async.HasLegacyGroup() err = async.Execute() if err != nil { log.Trace("call SC method failed", "error", err, "src", "async execution") return false, err } - if !async.IsComplete() { - var err error = nil - if !isLegacy { - async.SetResults(host.Output().GetVMOutput()) - err = async.Save() - } + if !async.IsComplete() || async.HasLegacyGroup() { + async.SetResults(host.Output().GetVMOutput()) + err = async.Save() return false, err } } else { diff --git a/vmhost/hostCore/host.go b/vmhost/hostCore/host.go index bbc3faa3b..baea6f9d9 100644 --- a/vmhost/hostCore/host.go +++ b/vmhost/hostCore/host.go @@ -2,6 +2,7 @@ package hostCore import ( "context" + "math" "runtime/debug" "sync" "time" @@ -83,7 +84,6 @@ func NewVMHost( blockChainHook vmcommon.BlockchainHook, hostParameters *vmhost.VMHostParameters, ) (vmhost.VMHost, error) { - if check.IfNil(blockChainHook) { return nil, vmhost.ErrNilBlockChainHook } @@ -366,6 +366,11 @@ func (host *vmHost) GetGasScheduleMap() config.GasScheduleMap { // RunSmartContractCreate executes the deployment of a new contract func (host *vmHost) RunSmartContractCreate(input *vmcommon.ContractCreateInput) (vmOutput *vmcommon.VMOutput, err error) { + err = validateVMInput(&input.VMInput) + if err != nil { + return nil, err + } + host.mutExecution.RLock() defer host.mutExecution.RUnlock() @@ -399,7 +404,7 @@ func (host *vmHost) RunSmartContractCreate(input *vmcommon.ContractCreateInput) }() vmOutput = host.doRunSmartContractCreate(input) - host.CompleteLogEntriesWithCallType(vmOutput, "DeploySmartContract") + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.DeploySmartContractString) logsFromErrors := host.createLogEntryFromErrors(input.CallerAddr, input.CallerAddr, "_init") if logsFromErrors != nil { @@ -427,6 +432,11 @@ func (host *vmHost) RunSmartContractCreate(input *vmcommon.ContractCreateInput) // RunSmartContractCall executes the call of an existing contract func (host *vmHost) RunSmartContractCall(input *vmcommon.ContractCallInput) (vmOutput *vmcommon.VMOutput, err error) { + err = validateVMInput(&input.VMInput) + if err != nil { + return nil, err + } + host.mutExecution.RLock() defer host.mutExecution.RUnlock() @@ -583,6 +593,14 @@ func (host *vmHost) CheckExecuteReadOnly() bool { return host.enableEpochsHandler.IsFlagEnabled(vmhost.CheckExecuteOnReadOnlyFlag) } +func validateVMInput(vmInput *vmcommon.VMInput) error { + if vmInput.GasProvided > math.MaxInt64 { + return vmhost.ErrInvalidGasProvided + } + + return nil +} + func (host *vmHost) setGasTracerEnabledIfLogIsTrace() { host.Metering().SetGasTracing(false) if logGasTrace.GetLevel() == logger.LogTrace { @@ -609,7 +627,7 @@ func (host *vmHost) logFromGasTracer(functionName string) { } } -// CompleteLogEntriesWithCallType sets the call type on a logn entry if it's not already filled +// CompleteLogEntriesWithCallType sets the call type on a log entry if it's not already filled func (host *vmHost) CompleteLogEntriesWithCallType(vmOutput *vmcommon.VMOutput, callType string) { for _, logEntry := range vmOutput.Logs { _, containsId := host.transferLogIdentifiers[string(logEntry.Identifier)] diff --git a/vmhost/hostCore/host_test.go b/vmhost/hostCore/host_test.go index 881191e05..72eb9a497 100644 --- a/vmhost/hostCore/host_test.go +++ b/vmhost/hostCore/host_test.go @@ -1,9 +1,11 @@ package hostCore import ( + "math" "testing" "github.com/multiversx/mx-chain-core-go/core" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" "github.com/multiversx/mx-chain-vm-common-go/parsers" worldmock "github.com/multiversx/mx-chain-vm-go/mock/world" @@ -96,3 +98,17 @@ func TestNewVMHost(t *testing.T) { require.ErrorIs(t, err, vmhost.ErrNilVMType) }) } + +func TestValidateVMInput(t *testing.T) { + vmInput := &vmcommon.VMInput{ + GasProvided: 0, + } + + vmInput.GasProvided = math.MaxUint64 + err := validateVMInput(vmInput) + require.ErrorIs(t, err, vmhost.ErrInvalidGasProvided) + + vmInput.GasProvided = math.MaxInt64 + err = validateVMInput(vmInput) + require.Nil(t, err) +} diff --git a/vmhost/hosttest/execution_benchmark_test.go b/vmhost/hosttest/execution_benchmark_test.go index 9657c69d0..8f2a61e40 100644 --- a/vmhost/hosttest/execution_benchmark_test.go +++ b/vmhost/hosttest/execution_benchmark_test.go @@ -1,6 +1,7 @@ package hostCoretest import ( + "math" "math/big" "math/rand" "strings" @@ -283,7 +284,7 @@ func deploy( CallValue: big.NewInt(0), CallType: vm.DirectCall, GasPrice: 0, - GasProvided: 0xFFFFFFFFFFFFFFFF, + GasProvided: math.MaxInt64, }, ContractCode: code, } diff --git a/vmhost/hosttest/execution_gas_test.go b/vmhost/hosttest/execution_gas_test.go index 21e464493..8bcca4078 100644 --- a/vmhost/hosttest/execution_gas_test.go +++ b/vmhost/hosttest/execution_gas_test.go @@ -168,7 +168,7 @@ func TestGasUsed_SingleContract_TransferFromChild(t *testing.T) { Identifier: []byte("transferValueOnly"), Address: test.ChildAddress, Topics: [][]byte{big.NewInt(testConfig.ChildBalance / 2).Bytes(), test.ParentAddress}, - Data: vmcommon.FormatLogDataForCall("ExecuteOnDestContext", "transferEGLDToParent", [][]byte{}), + Data: vmcommon.FormatLogDataForCall("BackTransfer", "", [][]byte{}), }) }) assert.Nil(t, err) @@ -264,7 +264,7 @@ func TestGasUsed_TwoContracts_ExecuteOnSameCtx(t *testing.T) { Identifier: []byte("transferValueOnly"), Address: test.ParentAddress, Topics: [][]byte{big.NewInt(testConfig.ChildBalance / 2).Bytes(), test.ParentAddress}, - Data: vmcommon.FormatLogDataForCall("ExecuteOnSameContext", "transferEGLDToParent", [][]byte{}), + Data: vmcommon.FormatLogDataForCall("BackTransfer", "", [][]byte{}), }) } }) @@ -710,11 +710,9 @@ func testGasUsedAsyncCallCrossShardInitCall(t *testing.T, isLegacy bool) { world.CurrentBlockInfo.BlockRound = 0 setZeroCodeCosts(host) setAsyncCosts(host, testConfig.GasLockCost) - if !isLegacy { - expectedStorages = append(expectedStorages, - test.CreateStoreEntry(test.ParentAddress).WithKey( - host.Storage().GetVmProtectedPrefix(vmhost.AsyncDataPrefix)).IgnoreValue()) - } + expectedStorages = append(expectedStorages, + test.CreateStoreEntry(test.ParentAddress).WithKey( + host.Storage().GetVmProtectedPrefix(vmhost.AsyncDataPrefix)).IgnoreValue()) }). AndAssertResults(func(world *worldmock.MockWorld, verify *test.VMOutputVerifier) { verify.Ok(). @@ -1447,10 +1445,10 @@ func testGasUsedESDTTransferThenExecuteAsyncCallSuccess(t *testing.T, isLegacy b } /* - ParentAddress.execESDTTransferAndAsyncCall -> ChildAddress.wasteGasOnNewphew (with async with ESDTTransfer) - ChildAddress.wasteGasOnNewphew -> NephewAddress.wasteGas - -> ParentAddress.callBack - ParentAddress.callBack -> ChildAddress.wasteGas +ParentAddress.execESDTTransferAndAsyncCall -> ChildAddress.wasteGasOnNephew (with async with ESDTTransfer) +ChildAddress.wasteGasOnNephew -> NephewAddress.wasteGas +-> ParentAddress.callBack +ParentAddress.callBack -> ChildAddress.wasteGas */ func TestGasUsed_ESDTTransfer_ThenExecuteAsyncCall_ThenExecuteOnDest(t *testing.T) { var parentAccount *worldmock.Account @@ -1795,7 +1793,7 @@ func testGasUsedESDTTransferInCallback(t *testing.T, isLegacy bool, numOfTransfe Address: test.ChildAddress, Topics: [][]byte{test.ESDTTestTokenName, {}, big.NewInt(int64(testConfig.CallbackESDTTokensToTransfer)).Bytes(), test.ParentAddress}, Data: vmcommon.FormatLogDataForCall( - "AsyncCall", + "BackTransfer", "ESDTTransfer", [][]byte{ test.ESDTTestTokenName, @@ -2072,19 +2070,30 @@ func TestGasUsed_TransferAndExecute_CrossShard(t *testing.T) { expectedTransfer := test.CreateTransferEntry(test.ParentAddress, contracts.GetChildAddressForTransfer(transfer), uint32(transfer+1)). WithData(big.NewInt(int64(transfer)).Bytes()). WithGasLimit(testConfig.GasProvidedToChild). + WithCallType(vm.DirectCall). WithValue(big.NewInt(testConfig.TransferFromParentToChild)) expectedTransfers = append(expectedTransfers, expectedTransfer) - expectedLogs = append(expectedLogs, vmcommon.LogEntry{ - Address: test.ParentAddress, - Topics: [][]byte{ - big.NewInt(testConfig.TransferFromParentToChild).Bytes(), - contracts.GetChildAddressForTransfer(transfer)}, - Data: vmcommon.FormatLogDataForCall( - "DirectCall", - contracts.TransferAndExecuteFuncName, - [][]byte{{byte(noOfTransfers)}}), - Identifier: []byte("transferValueOnly"), - }) + if transfer == 0 { + expectedLog := vmcommon.LogEntry{ + Address: test.ParentAddress, + Topics: [][]byte{ + big.NewInt(testConfig.TransferFromParentToChild).Bytes(), + contracts.GetChildAddressForTransfer(transfer)}, + Data: [][]byte{[]byte("DirectCall"), []byte("")}, + Identifier: []byte("transferValueOnly"), + } + expectedLogs = append(expectedLogs, expectedLog) + } else { + expectedLog := vmcommon.LogEntry{ + Address: test.ParentAddress, + Topics: [][]byte{ + big.NewInt(testConfig.TransferFromParentToChild).Bytes(), + contracts.GetChildAddressForTransfer(transfer)}, + Data: [][]byte{[]byte("TransferAndExecute"), big.NewInt(int64(transfer)).Bytes()}, + Identifier: []byte("transferValueOnly"), + } + expectedLogs = append(expectedLogs, expectedLog) + } } gasRemaining := testConfig.GasProvided - testConfig.GasUsedByParent - uint64(noOfTransfers)*testConfig.GasProvidedToChild diff --git a/vmhost/hosttest/execution_test.go b/vmhost/hosttest/execution_test.go index fb3a8b918..f5231bd3b 100644 --- a/vmhost/hosttest/execution_test.go +++ b/vmhost/hosttest/execution_test.go @@ -448,6 +448,94 @@ func TestExecution_Deploy_DisallowFloatingPoint(t *testing.T) { }) } +func TestExecution_DeployWASM_GasValidation(t *testing.T) { + var gasProvided uint64 + gasUsedByDeployment := uint64(570) + + inputBuilder := test.CreateTestContractCreateInputBuilder(). + WithContractCode(test.GetTestSCCode("init-correct", "../../")). + WithCallValue(88). + WithArguments([]byte{0}) + + testCase := test.BuildInstanceCreatorTest(t). + WithAddress(newAddress) + + gasProvided = math.MaxUint64 + inputBuilder.WithGasProvided(gasProvided) + testCase.WithInput(inputBuilder.Build()) + _, _, err := testCase.RunTest(true) + require.ErrorIs(t, err, vmhost.ErrInvalidGasProvided) + + gasProvided = math.MaxInt64 + 1 + inputBuilder.WithGasProvided(gasProvided) + testCase.WithInput(inputBuilder.Build()) + _, _, err = testCase.RunTest(true) + require.ErrorIs(t, err, vmhost.ErrInvalidGasProvided) + + gasProvided = math.MaxInt64 + input := inputBuilder.WithGasProvided(gasProvided).Build() + testCase.WithInput(input) + testCase.AndAssertResults(func(blockchainHook *contextmock.BlockchainHookStub, verify *test.VMOutputVerifier) { + verify.Ok(). + ReturnData([]byte("init successful")). + GasRemaining(gasProvided-gasUsedByDeployment). + Nonce([]byte("caller"), 24). + Code(newAddress, input.ContractCode). + BalanceDelta(newAddress, 88) + }) + + gasProvided = uint64(1000) + input = inputBuilder.WithGasProvided(gasProvided).Build() + testCase.WithInput(input) + testCase.AndAssertResults(func(blockchainHook *contextmock.BlockchainHookStub, verify *test.VMOutputVerifier) { + verify.Ok(). + ReturnData([]byte("init successful")). + GasRemaining(gasProvided-gasUsedByDeployment). + Nonce([]byte("caller"), 24). + Code(newAddress, input.ContractCode). + BalanceDelta(newAddress, 88) + }) +} + +func TestExecution_SingleContract_GasValidation(t *testing.T) { + testConfig := makeTestConfig() + + inputBuilder := test.CreateTestContractCallInputBuilder(). + WithRecipientAddr(test.ParentAddress). + WithFunction("wasteGas") + + testCase := test.BuildMockInstanceCallTest(t). + WithContracts( + test.CreateMockContract(test.ParentAddress). + WithBalance(testConfig.ParentBalance). + WithConfig(testConfig). + WithMethods(contracts.WasteGasParentMock)). + WithSetup(func(host vmhost.VMHost, world *worldmock.MockWorld) { + setZeroCodeCosts(host) + }) + + testConfig.GasProvided = math.MaxUint64 + inputBuilder.WithGasProvided(testConfig.GasProvided) + testCase.WithInput(inputBuilder.Build()) + _, _, err := testCase.RunTest(nil, true, test.RunTest) + require.ErrorIs(t, err, vmhost.ErrInvalidGasProvided) + + testConfig.GasProvided = math.MaxInt64 + 1 + inputBuilder.WithGasProvided(testConfig.GasProvided) + testCase.WithInput(inputBuilder.Build()) + _, _, err = testCase.RunTest(nil, true, test.RunTest) + require.ErrorIs(t, err, vmhost.ErrInvalidGasProvided) + + testConfig.GasProvided = math.MaxInt64 + inputBuilder.WithGasProvided(testConfig.GasProvided) + testCase.WithInput(inputBuilder.Build()) + _, _ = testCase.AndAssertResults(func(world *worldmock.MockWorld, verify *test.VMOutputVerifier) { + verify.Ok(). + GasUsed(test.ParentAddress, testConfig.GasUsedByParent). + GasRemaining(testConfig.GasProvided - testConfig.GasUsedByParent) + }) +} + func TestExecution_CallGetUserAccountErr(t *testing.T) { errGetAccount := errors.New("get code error") test.BuildInstanceCallTest(t). @@ -2781,6 +2869,7 @@ func TestExecution_AsyncCall_CallBackFails(t *testing.T) { Ok(). // TODO matei-p enable this for R2 //UserError(). + //ReturnMessage("callBack error"). GasUsed(test.ParentAddress, 198656). GasUsed(test.ChildAddress, 1297). @@ -2912,7 +3001,7 @@ func TestExecution_CreateNewContract_Success(t *testing.T) { Identifier: []byte("transferValueOnly"), Address: test.ParentAddress, Topics: [][]byte{{42}, childAddress}, - Data: vmcommon.FormatLogDataForCall("CreateSmartContract", "init", [][]byte{{0}}), + Data: vmcommon.FormatLogDataForCall("DeploySmartContract", "init", [][]byte{{0}}), }) }) } @@ -3072,7 +3161,7 @@ func TestExecution_CreateNewContract_IsSmartContract(t *testing.T) { Identifier: []byte("transferValueOnly"), Address: createdNewAddr[0], Topics: [][]byte{{42}, createdNewAddr[1]}, - Data: vmcommon.FormatLogDataForCall("CreateSmartContract", "init", [][]byte{createdNewAddr[0]}), + Data: vmcommon.FormatLogDataForCall("DeploySmartContract", "init", [][]byte{createdNewAddr[0]}), }) }) } diff --git a/vmhost/hosttest/managedei_test.go b/vmhost/hosttest/managedei_test.go index 7800535ef..cfc16abc2 100644 --- a/vmhost/hosttest/managedei_test.go +++ b/vmhost/hosttest/managedei_test.go @@ -5,6 +5,7 @@ import ( "crypto/ed25519" "crypto/elliptic" "encoding/hex" + "fmt" "math/big" "strings" "testing" @@ -309,7 +310,7 @@ func Test_BigIntToString(t *testing.T) { // Real contracts always check first that the big int fits. // This special test case represents an intentionally badly written contract. -func bigIntToInt64MockContract(parentInstance *mock.InstanceMock, config interface{}) { +func bigIntToInt64MockContract(parentInstance *mock.InstanceMock, _ interface{}) { parentInstance.AddMockMethod("testFunction", func() *mock.InstanceMock { vmHooksImpl := vmhooks.NewVMHooksImpl(parentInstance.Host) @@ -1395,3 +1396,142 @@ func Test_ManagedIsBuiltinFunction(t *testing.T) { }) assert.Nil(t, err) } + +func Test_Direct_ManagedGetBackTransfers(t *testing.T) { + testConfig := makeTestConfig() + egldTransfer := big.NewInt(2) + initialESDTTokenBalance := uint64(100) + testConfig.ESDTTokensToTransfer = 5 + + _, err := test.BuildMockInstanceCallTest(t). + WithContracts( + test.CreateMockContract(test.ParentAddress). + WithBalance(testConfig.ParentBalance). + WithConfig(testConfig). + WithMethods(func(parentInstance *mock.InstanceMock, config interface{}) { + parentInstance.AddMockMethod("callChild", func() *mock.InstanceMock { + host := parentInstance.Host + input := test.DefaultTestContractCallInput() + input.GasProvided = testConfig.GasProvidedToChild + input.CallerAddr = test.ParentAddress + input.RecipientAddr = test.ChildAddress + input.Function = "childFunction" + returnValue := contracts.ExecuteOnDestContextInMockContracts(host, input) + if returnValue != 0 { + host.Runtime().FailExecution(fmt.Errorf("return value %d", returnValue)) + } + managedTypes := host.ManagedTypes() + esdtTransfers, egld := managedTypes.GetBackTransfers() + assert.Equal(t, 1, len(esdtTransfers)) + assert.Equal(t, test.ESDTTestTokenName, esdtTransfers[0].ESDTTokenName) + assert.Equal(t, big.NewInt(0).SetUint64(testConfig.ESDTTokensToTransfer), esdtTransfers[0].ESDTValue) + assert.Equal(t, egld, egldTransfer) + return parentInstance + }) + }), + test.CreateMockContract(test.ChildAddress). + WithBalance(testConfig.ChildBalance). + WithConfig(testConfig). + WithMethods(func(parentInstance *mock.InstanceMock, config interface{}) { + parentInstance.AddMockMethod("childFunction", func() *mock.InstanceMock { + host := parentInstance.Host + + valueBytes := egldTransfer.Bytes() + err := host.Output().Transfer( + test.ParentAddress, + test.ChildAddress, 0, 0, big.NewInt(0).SetBytes(valueBytes), nil, []byte{}, vm.DirectCall) + if err != nil { + host.Runtime().FailExecution(err) + } + + transfer := &vmcommon.ESDTTransfer{ + ESDTValue: big.NewInt(int64(testConfig.ESDTTokensToTransfer)), + ESDTTokenName: test.ESDTTestTokenName, + ESDTTokenType: 0, + ESDTTokenNonce: 0, + } + + ret := vmhooks.TransferESDTNFTExecuteWithTypedArgs( + host, + test.ParentAddress, + []*vmcommon.ESDTTransfer{transfer}, + int64(testConfig.GasProvidedToChild), + nil, + nil) + if ret != 0 { + host.Runtime().FailExecution(fmt.Errorf("Transfer ESDT failed")) + } + + return parentInstance + }) + }), + ). + WithSetup(func(host vmhost.VMHost, world *worldmock.MockWorld) { + childAccount := world.AcctMap.GetAccount(test.ChildAddress) + _ = childAccount.SetTokenBalanceUint64(test.ESDTTestTokenName, 0, initialESDTTokenBalance) + createMockBuiltinFunctions(t, host, world) + setZeroCodeCosts(host) + }). + WithInput(test.CreateTestContractCallInputBuilder(). + WithRecipientAddr(test.ParentAddress). + WithGasProvided(testConfig.GasProvided). + WithFunction("callChild"). + Build()). + AndAssertResults(func(world *worldmock.MockWorld, verify *test.VMOutputVerifier) { + verify. + Ok() + }) + assert.Nil(t, err) +} + +func Test_Async_ManagedGetBackTransfers(t *testing.T) { + testConfig := makeTestConfig() + initialESDTTokenBalance := uint64(100) + testConfig.GasProvided = 10_000 + testConfig.GasProvidedToChild = 1000 + testConfig.ESDTTokensToTransfer = 5 + testConfig.SuccessCallback = "myCallback" + testConfig.ErrorCallback = "myCallback" + testConfig.TransferFromChildToParent = 2 + testConfig.ParentAddress = test.ParentAddress + testConfig.ChildAddress = test.ChildAddress + testConfig.NephewAddress = test.NephewAddress + + _, err := test.BuildMockInstanceCallTest(t). + WithContracts( + test.CreateMockContract(test.ParentAddress). + WithBalance(testConfig.ParentBalance). + WithConfig(testConfig). + WithCodeMetadata([]byte{0, 0}). + WithMethods(contracts.BackTransfer_ParentCallsChild), + test.CreateMockContract(test.ChildAddress). + WithBalance(testConfig.ChildBalance). + WithConfig(testConfig). + WithMethods( + contracts.BackTransfer_ChildMakesAsync, + contracts.BackTransfer_ChildCallback, + ), + test.CreateMockContract(test.NephewAddress). + WithBalance(testConfig.ChildBalance). + WithConfig(testConfig). + WithMethods(contracts.WasteGasChildMock), + ). + WithSetup(func(host vmhost.VMHost, world *worldmock.MockWorld) { + childAccount := world.AcctMap.GetAccount(test.ChildAddress) + _ = childAccount.SetTokenBalanceUint64(test.ESDTTestTokenName, 0, initialESDTTokenBalance) + createMockBuiltinFunctions(t, host, world) + setZeroCodeCosts(host) + host.Metering().GasSchedule().BaseOpsAPICost.AsyncCallbackGasLock = 0 + }). + WithInput(test.CreateTestContractCallInputBuilder(). + WithRecipientAddr(test.ParentAddress). + WithGasProvided(testConfig.GasProvided). + WithFunction("callChild"). + WithArguments([]byte{1}). + Build()). + AndAssertResults(func(world *worldmock.MockWorld, verify *test.VMOutputVerifier) { + verify. + Ok() + }) + assert.Nil(t, err) +} diff --git a/vmhost/hosttest/mex_benchmark_test.go b/vmhost/hosttest/mex_benchmark_test.go index 1929969ae..d75f02fe2 100644 --- a/vmhost/hosttest/mex_benchmark_test.go +++ b/vmhost/hosttest/mex_benchmark_test.go @@ -1,6 +1,7 @@ package hostCoretest import ( + "math" "math/big" "testing" "time" @@ -135,7 +136,7 @@ func (mex *MEXSetup) Deploy() { big.NewInt(int64(mex.TotalFeePercent)).Bytes(), big.NewInt(int64(mex.SpecialFeePercent)).Bytes(), ). - WithGasProvided(0xFFFFFFFFFFFFFFFF). + WithGasProvided(math.MaxInt64). Build() world.NewAddressMocks = append(world.NewAddressMocks, &worldmock.NewAddressMock{ @@ -171,7 +172,7 @@ func (mex *MEXSetup) setLPToken() { WithRecipientAddr(mex.PairAddress). WithFunction("setLpTokenIdentifier"). WithArguments(mex.LPToken). - WithGasProvided(0xFFFFFFFFFFFFFFFF). + WithGasProvided(math.MaxInt64). Build() vmOutput, err := host.RunSmartContractCall(vmInput) @@ -191,7 +192,7 @@ func (mex *MEXSetup) setActiveState() { WithCallerAddr(mex.OwnerAddress). WithRecipientAddr(mex.PairAddress). WithFunction("resume"). - WithGasProvided(0xFFFFFFFFFFFFFFFF). + WithGasProvided(math.MaxInt64). Build() vmOutput, err := host.RunSmartContractCall(vmInput) @@ -212,7 +213,7 @@ func (mex *MEXSetup) setMaxObservationsPerRecord() { WithRecipientAddr(mex.PairAddress). WithFunction("setMaxObservationsPerRecord"). WithArguments(big.NewInt(int64(mex.MaxObservationsPerRecord)).Bytes()). - WithGasProvided(0xFFFFFFFFFFFFFFFF). + WithGasProvided(math.MaxInt64). Build() vmOutput, err := host.RunSmartContractCall(vmInput) @@ -255,7 +256,7 @@ func (mex *MEXSetup) AddLiquidity( big.NewInt(int64(minWEGLDAmount)).Bytes(), big.NewInt(int64(minMEXAmount)).Bytes(), ). - WithGasProvided(0xFFFFFFFFFFFFFFFF) + WithGasProvided(math.MaxInt64) vmInputBuiler. WithESDTTokenName(mex.WEGLDToken). @@ -300,7 +301,7 @@ func (mex *MEXSetup) CreateSwapVMInputs( rightToken, big.NewInt(int64(rightAmount)).Bytes(), ). - WithGasProvided(0xFFFFFFFFFFF) + WithGasProvided(math.MaxInt64) vmInput := vmInputBuiler.Build() @@ -350,7 +351,7 @@ func (mex *MEXSetup) createMultiESDTTransferVMInput( CallValue: big.NewInt(0), CallType: vm.DirectCall, GasPrice: 1, - GasProvided: 0xFFFFFFFF, + GasProvided: math.MaxInt64, GasLocked: 0, }, RecipientAddr: sender, diff --git a/vmhost/interface.go b/vmhost/interface.go index bcfa03888..30938dfad 100644 --- a/vmhost/interface.go +++ b/vmhost/interface.go @@ -216,6 +216,9 @@ type ManagedTypesContext interface { ManagedMapGet(mMapHandle int32, keyHandle int32, outValueHandle int32) error ManagedMapRemove(mMapHandle int32, keyHandle int32, outValueHandle int32) error ManagedMapContains(mMapHandle int32, keyHandle int32) (bool, error) + GetBackTransfers() ([]*vmcommon.ESDTTransfer, *big.Int) + AddValueOnlyBackTransfer(value *big.Int) + AddBackTransfers(transfers []*vmcommon.ESDTTransfer) } // OutputContext defines the functionality needed for interacting with the output context @@ -229,6 +232,7 @@ type OutputContext interface { GetOutputAccounts() map[string]*vmcommon.OutputAccount DeleteOutputAccount(address []byte) WriteLog(address []byte, topics [][]byte, data [][]byte) + WriteLogWithIdentifier(address []byte, topics [][]byte, data [][]byte, identifier []byte) TransferValueOnly(destination []byte, sender []byte, value *big.Int, checkPayable bool) error Transfer(destination []byte, sender []byte, gasLimit uint64, gasLocked uint64, value *big.Int, asyncData []byte, input []byte, callType vm.CallType) error TransferESDT(transfersArgs *ESDTTransfersArgs, callInput *vmcommon.ContractCallInput) (uint64, error) @@ -350,6 +354,7 @@ type AsyncContext interface { SetContextCallback(callbackName string, data []byte, gas uint64) error HasCallback() bool GetCallerAddress() []byte + GetParentAddress() []byte GetCallerCallID() []byte GetReturnData() []byte SetReturnData(data []byte) @@ -360,7 +365,7 @@ type AsyncContext interface { LoadParentContext() error Save() error - DeleteFromAddress(address []byte) error + DeleteFromCallID(address []byte) error GetCallID() []byte GetCallbackAsyncInitiatorCallID() []byte diff --git a/vmhost/vmhooks/baseOps.go b/vmhost/vmhooks/baseOps.go index 572646cb4..935f19185 100644 --- a/vmhost/vmhooks/baseOps.go +++ b/vmhost/vmhooks/baseOps.go @@ -803,12 +803,13 @@ func TransferValueExecuteWithTypedArgs( if host.AreInSameShard(sender, dest) && contractCallInput != nil && host.Blockchain().IsSmartContract(dest) { logEEI.Trace("eGLD pre-transfer execution begin") - _, err = executeOnDestContextFromAPI(host, contractCallInput) + vmOutput, err := executeOnDestContextFromAPI(host, contractCallInput) if err != nil { logEEI.Trace("eGLD pre-transfer execution failed", "error", err) WithFaultAndHost(host, err, runtime.BaseOpsErrorShouldFailExecution()) return 1 } + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.TransferAndExecuteString) return 0 } @@ -2675,11 +2676,13 @@ func ExecuteOnDestContextWithTypedArgs( return 1 } - _, err = executeOnDestContextFromAPI(host, contractCallInput) + vmOutput, err := executeOnDestContextFromAPI(host, contractCallInput) if WithFaultAndHost(host, err, runtime.BaseOpsErrorShouldFailExecution()) { return 1 } + host.CompleteLogEntriesWithCallType(vmOutput, vmhost.ExecuteOnDestContextString) + return 0 } @@ -3179,7 +3182,7 @@ func prepareIndirectContractCallInput( } func (context *VMHooksImpl) getArgumentsFromMemory( - host vmhost.VMHost, + _ vmhost.VMHost, numArguments int32, argumentsLengthOffset executor.MemPtr, dataOffset executor.MemPtr, @@ -3219,13 +3222,12 @@ func createInt32Array(rawData []byte, numIntegers int32) []int32 { return integers } -func executeOnDestContextFromAPI(host vmhost.VMHost, input *vmcommon.ContractCallInput) (vmOutput *vmcommon.VMOutput, err error) { +func executeOnDestContextFromAPI(host vmhost.VMHost, input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error) { host.Async().SetAsyncArgumentsForCall(input) vmOutput, isChildComplete, err := host.ExecuteOnDestContext(input) if err != nil { return nil, err } - host.CompleteLogEntriesWithCallType(vmOutput, "ExecuteOnDestContext") err = host.Async().CompleteChildConditional(isChildComplete, nil, 0) if err != nil { diff --git a/vmhost/vmhooks/generate/cmd/eiGenMain.go b/vmhost/vmhooks/generate/cmd/eiGenMain.go index 646acc2d3..1579d0748 100644 --- a/vmhost/vmhooks/generate/cmd/eiGenMain.go +++ b/vmhost/vmhooks/generate/cmd/eiGenMain.go @@ -16,9 +16,6 @@ import ( const pathToApiPackage = "./" const pathToRustRepoConfigFile = "wasm-vm-executor-rs-path.txt" -// Until we merge the `feat/wasmer2`, there are some files that are not supposed to be generated. -const wasmer2Branch = true - func initEIMetadata() *eapigen.EIMetadata { return &eapigen.EIMetadata{ Groups: []*eapigen.EIGroup{ @@ -48,15 +45,14 @@ func main() { writeVMHooks(eiMetadata) writeVMHooksWrapper(eiMetadata) writeWasmer1ImportsCgo(eiMetadata) - if wasmer2Branch { - writeWasmer2ImportsCgo(eiMetadata) - writeWasmer2Names(eiMetadata) - } + writeWasmer2ImportsCgo(eiMetadata) + writeWasmer2Names(eiMetadata) writeNamesForMockExecutor(eiMetadata) tryCreateRustOutputDirectory() + writeRustVMHooksNames(eiMetadata) writeRustVMHooksTrait(eiMetadata) writeRustCapiVMHooks(eiMetadata) writeRustCapiVMHooksPointers(eiMetadata) @@ -64,10 +60,8 @@ func main() { fmt.Printf("Generated code for %d executor callback methods.\n", len(eiMetadata.AllFunctions)) - if wasmer2Branch { - writeExecutorOpcodeCosts() - writeWasmer2OpcodeCost() - } + writeExecutorOpcodeCosts() + writeWasmer2OpcodeCost() writeWASMOpcodeCostFuncHelpers() writeWASMOpcodeCostConfigHelpers() writeOpcodeCostFuncHelpers() @@ -128,6 +122,12 @@ func tryCreateRustOutputDirectory() { fmt.Println("Output directory already exists.") } +func writeRustVMHooksNames(eiMetadata *eapigen.EIMetadata) { + out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/ei_1_5.rs") + defer out.Close() + eapigen.WriteRustHookNames(out, eiMetadata) +} + func writeRustVMHooksTrait(eiMetadata *eapigen.EIMetadata) { out := eapigen.NewEIGenWriter(pathToApiPackage, "generate/cmd/output/vm_hooks.rs") defer out.Close() @@ -207,27 +207,27 @@ func tryCopyFilesToRustExecutorRepo() { fmt.Printf("Copying generated Rust files to '%s':\n", rustExecutorPath) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/vm_hooks.rs"), - filepath.Join(rustExecutorPath, "exec-service/src/vm_hooks.rs"), + filepath.Join(rustExecutorPath, "vm-executor/src/vm_hooks.rs"), ) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/opcode_cost.rs"), - filepath.Join(rustExecutorPath, "exec-service/src/opcode_cost.rs"), + filepath.Join(rustExecutorPath, "vm-executor/src/opcode_cost.rs"), ) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/capi_vm_hook.rs"), - filepath.Join(rustExecutorPath, "exec-c-api/src/capi_vm_hooks.rs"), + filepath.Join(rustExecutorPath, "c-api/src/capi_vm_hooks.rs"), ) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/capi_vm_hook_pointers.rs"), - filepath.Join(rustExecutorPath, "exec-c-api/src/capi_vm_hook_pointers.rs"), + filepath.Join(rustExecutorPath, "c-api/src/capi_vm_hook_pointers.rs"), ) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_imports.rs"), - filepath.Join(rustExecutorPath, "exec-service-wasmer/src/wasmer_imports.rs"), + filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_imports.rs"), ) copyFile( filepath.Join(pathToApiPackage, "generate/cmd/output/wasmer_metering_helpers.rs"), - filepath.Join(rustExecutorPath, "exec-service-wasmer/src/wasmer_metering_helpers.rs"), + filepath.Join(rustExecutorPath, "vm-executor-wasmer/src/wasmer_metering_helpers.rs"), ) } diff --git a/vmhost/vmhooks/generate/eiGenWriteRustCapiVMHooks.go b/vmhost/vmhooks/generate/eiGenWriteRustCapiVMHooks.go index feb189132..03e47027b 100644 --- a/vmhost/vmhooks/generate/eiGenWriteRustCapiVMHooks.go +++ b/vmhost/vmhooks/generate/eiGenWriteRustCapiVMHooks.go @@ -10,7 +10,7 @@ func WriteRustCapiVMHooks(out *eiGenWriter, eiMetadata *EIMetadata) { out.WriteString(` use std::ffi::c_void; -use multiversx_vm_executor::{MemLength, MemPtr}; +use multiversx_chain_vm_executor::{MemLength, MemPtr}; use crate::capi_vm_hook_pointers::vm_exec_vm_hook_c_func_pointers; @@ -38,7 +38,7 @@ impl CapiVMHooks { } #[rustfmt::skip] -impl multiversx_vm_executor::VMHooks for CapiVMHooks { +impl multiversx_chain_vm_executor::VMHooks for CapiVMHooks { fn set_vm_hooks_ptr(&mut self, vm_hooks_ptr: *mut c_void) { self.vm_hooks_ptr = vm_hooks_ptr; } diff --git a/vmhost/vmhooks/generate/eiGenWriteRustVMHooksNames.go b/vmhost/vmhooks/generate/eiGenWriteRustVMHooksNames.go new file mode 100644 index 000000000..6d447af26 --- /dev/null +++ b/vmhost/vmhooks/generate/eiGenWriteRustVMHooksNames.go @@ -0,0 +1,22 @@ +package vmhooksgenerate + +import ( + "fmt" +) + +func WriteRustHookNames( + out *eiGenWriter, + eiMetadata *EIMetadata, +) { + autoGeneratedHeader(out) + out.WriteString("\n") + out.WriteString("pub const VM_1_5_NAMES: &[&str] = &[") + + for _, funcMetadata := range eiMetadata.AllFunctions { + out.WriteString(fmt.Sprintf("\n\t\"%s\",", lowerInitial(funcMetadata.Name))) + } + + out.WriteString(` +]; +`) +} diff --git a/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go b/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go index f98190514..0ab670c6a 100644 --- a/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go +++ b/vmhost/vmhooks/generate/eiGenWriteRustWasmerMeteringHelpers.go @@ -12,7 +12,7 @@ const localCostName = "localallocate" // WriteRustWasmerMeteringHelpers generates code for wasmer_metering_helpers.rs func WriteRustWasmerMeteringHelpers(out *eiGenWriter) { autoGeneratedHeader(out) - out.WriteString("\nuse multiversx_vm_executor::OpcodeCost;\n") + out.WriteString("\nuse multiversx_chain_vm_executor::OpcodeCost;\n") out.WriteString("use wasmer::wasmparser::Operator;\n\n") readFile, err := os.Open("generate/cmd/input/wasmer2_opcodes_short.txt") diff --git a/vmhost/vmhooks/managedei.go b/vmhost/vmhooks/managedei.go index 6e22bdded..a6ffcf439 100644 --- a/vmhost/vmhooks/managedei.go +++ b/vmhost/vmhooks/managedei.go @@ -245,6 +245,23 @@ func (context *VMHooksImpl) ManagedGetMultiESDTCallValue(multiCallValueHandle in managedType.SetBytes(multiCallValueHandle, multiCallBytes) } +// ManagedGetBackTransfers VMHooks implementation. +// @autogenerate(VMHooks) +func (context *VMHooksImpl) ManagedGetBackTransfers(esdtTransfersValueHandle int32, callValueHandle int32) { + metering := context.GetMeteringContext() + managedType := context.GetManagedTypesContext() + + gasToUse := metering.GasSchedule().BaseOpsAPICost.GetCallValue + metering.UseGasAndAddTracedGas(managedGetMultiESDTCallValueName, gasToUse) + + esdtTransfers, transferValue := managedType.GetBackTransfers() + multiCallBytes := writeESDTTransfersToBytes(managedType, esdtTransfers) + managedType.ConsumeGasForBytes(multiCallBytes) + + managedType.SetBytes(esdtTransfersValueHandle, multiCallBytes) + managedType.SetBytes(callValueHandle, transferValue.Bytes()) +} + // ManagedGetESDTBalance VMHooks implementation. // @autogenerate(VMHooks) func (context *VMHooksImpl) ManagedGetESDTBalance(addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32) { diff --git a/wasmer/wasmerImportsCgo.go b/wasmer/wasmerImportsCgo.go index 9c3934ed7..da92dbb44 100644 --- a/wasmer/wasmerImportsCgo.go +++ b/wasmer/wasmerImportsCgo.go @@ -102,6 +102,7 @@ package wasmer // extern void v1_5_managedGetPrevBlockRandomSeed(void* context, int32_t resultHandle); // extern void v1_5_managedGetReturnData(void* context, int32_t resultID, int32_t resultHandle); // extern void v1_5_managedGetMultiESDTCallValue(void* context, int32_t multiCallValueHandle); +// extern void v1_5_managedGetBackTransfers(void* context, int32_t esdtTransfersValueHandle, int32_t callValueHandle); // extern void v1_5_managedGetESDTBalance(void* context, int32_t addressHandle, int32_t tokenIDHandle, long long nonce, int32_t valueHandle); // extern void v1_5_managedGetESDTTokenData(void* context, int32_t addressHandle, int32_t tokenIDHandle, long long nonce, int32_t valueHandle, int32_t propertiesHandle, int32_t hashHandle, int32_t nameHandle, int32_t attributesHandle, int32_t creatorHandle, int32_t royaltiesHandle, int32_t urisHandle); // extern void v1_5_managedAsyncCall(void* context, int32_t destHandle, int32_t valueHandle, int32_t functionHandle, int32_t argumentsHandle); @@ -731,6 +732,11 @@ func populateWasmerImports(imports *wasmerImports) error { return err } + err = imports.append("managedGetBackTransfers", v1_5_managedGetBackTransfers, C.v1_5_managedGetBackTransfers) + if err != nil { + return err + } + err = imports.append("managedGetESDTBalance", v1_5_managedGetESDTBalance, C.v1_5_managedGetESDTBalance) if err != nil { return err @@ -2095,6 +2101,12 @@ func v1_5_managedGetMultiESDTCallValue(context unsafe.Pointer, multiCallValueHan vmHooks.ManagedGetMultiESDTCallValue(multiCallValueHandle) } +//export v1_5_managedGetBackTransfers +func v1_5_managedGetBackTransfers(context unsafe.Pointer, esdtTransfersValueHandle int32, callValueHandle int32) { + vmHooks := getVMHooksFromContextRawPtr(context) + vmHooks.ManagedGetBackTransfers(esdtTransfersValueHandle, callValueHandle) +} + //export v1_5_managedGetESDTBalance func v1_5_managedGetESDTBalance(context unsafe.Pointer, addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32) { vmHooks := getVMHooksFromContextRawPtr(context) diff --git a/wasmer2/libvmexeccapi.dylib b/wasmer2/libvmexeccapi.dylib index 8ecccadea..27f527009 100644 Binary files a/wasmer2/libvmexeccapi.dylib and b/wasmer2/libvmexeccapi.dylib differ diff --git a/wasmer2/libvmexeccapi.h b/wasmer2/libvmexeccapi.h index 7b7b5f688..f4a0da9a2 100644 --- a/wasmer2/libvmexeccapi.h +++ b/wasmer2/libvmexeccapi.h @@ -129,6 +129,7 @@ typedef struct { void (*managed_get_prev_block_random_seed_func_ptr)(void *context, int32_t result_handle); void (*managed_get_return_data_func_ptr)(void *context, int32_t result_id, int32_t result_handle); void (*managed_get_multi_esdt_call_value_func_ptr)(void *context, int32_t multi_call_value_handle); + void (*managed_get_back_transfers_func_ptr)(void *context, int32_t esdt_transfers_value_handle, int32_t call_value_handle); void (*managed_get_esdt_balance_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce, int32_t value_handle); void (*managed_get_esdt_token_data_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce, int32_t value_handle, int32_t properties_handle, int32_t hash_handle, int32_t name_handle, int32_t attributes_handle, int32_t creator_handle, int32_t royalties_handle, int32_t uris_handle); void (*managed_async_call_func_ptr)(void *context, int32_t dest_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle); diff --git a/wasmer2/libvmexeccapi.so b/wasmer2/libvmexeccapi.so index d092b77cf..7788f9de4 100644 Binary files a/wasmer2/libvmexeccapi.so and b/wasmer2/libvmexeccapi.so differ diff --git a/wasmer2/wasmer2ImportsCgo.go b/wasmer2/wasmer2ImportsCgo.go index 1baeb6ae4..b24feb6ef 100644 --- a/wasmer2/wasmer2ImportsCgo.go +++ b/wasmer2/wasmer2ImportsCgo.go @@ -102,6 +102,7 @@ package wasmer2 // extern void w2_managedGetPrevBlockRandomSeed(void* context, int32_t resultHandle); // extern void w2_managedGetReturnData(void* context, int32_t resultID, int32_t resultHandle); // extern void w2_managedGetMultiESDTCallValue(void* context, int32_t multiCallValueHandle); +// extern void w2_managedGetBackTransfers(void* context, int32_t esdtTransfersValueHandle, int32_t callValueHandle); // extern void w2_managedGetESDTBalance(void* context, int32_t addressHandle, int32_t tokenIDHandle, long long nonce, int32_t valueHandle); // extern void w2_managedGetESDTTokenData(void* context, int32_t addressHandle, int32_t tokenIDHandle, long long nonce, int32_t valueHandle, int32_t propertiesHandle, int32_t hashHandle, int32_t nameHandle, int32_t attributesHandle, int32_t creatorHandle, int32_t royaltiesHandle, int32_t urisHandle); // extern void w2_managedAsyncCall(void* context, int32_t destHandle, int32_t valueHandle, int32_t functionHandle, int32_t argumentsHandle); @@ -367,6 +368,7 @@ func populateCgoFunctionPointers() *cWasmerVmHookPointers { managed_get_prev_block_random_seed_func_ptr: funcPointer(C.w2_managedGetPrevBlockRandomSeed), managed_get_return_data_func_ptr: funcPointer(C.w2_managedGetReturnData), managed_get_multi_esdt_call_value_func_ptr: funcPointer(C.w2_managedGetMultiESDTCallValue), + managed_get_back_transfers_func_ptr: funcPointer(C.w2_managedGetBackTransfers), managed_get_esdt_balance_func_ptr: funcPointer(C.w2_managedGetESDTBalance), managed_get_esdt_token_data_func_ptr: funcPointer(C.w2_managedGetESDTTokenData), managed_async_call_func_ptr: funcPointer(C.w2_managedAsyncCall), @@ -1079,6 +1081,12 @@ func w2_managedGetMultiESDTCallValue(context unsafe.Pointer, multiCallValueHandl vmHooks.ManagedGetMultiESDTCallValue(multiCallValueHandle) } +//export w2_managedGetBackTransfers +func w2_managedGetBackTransfers(context unsafe.Pointer, esdtTransfersValueHandle int32, callValueHandle int32) { + vmHooks := getVMHooksFromContextRawPtr(context) + vmHooks.ManagedGetBackTransfers(esdtTransfersValueHandle, callValueHandle) +} + //export w2_managedGetESDTBalance func w2_managedGetESDTBalance(context unsafe.Pointer, addressHandle int32, tokenIDHandle int32, nonce int64, valueHandle int32) { vmHooks := getVMHooksFromContextRawPtr(context) diff --git a/wasmer2/wasmer2Names.go b/wasmer2/wasmer2Names.go index b7fd2603b..7fa7c4d0b 100644 --- a/wasmer2/wasmer2Names.go +++ b/wasmer2/wasmer2Names.go @@ -100,6 +100,7 @@ var functionNames = map[string]struct{}{ "managedGetPrevBlockRandomSeed": empty, "managedGetReturnData": empty, "managedGetMultiESDTCallValue": empty, + "managedGetBackTransfers": empty, "managedGetESDTBalance": empty, "managedGetESDTTokenData": empty, "managedAsyncCall": empty,