diff --git a/config/config.toml b/config/config.toml index 98eecd6c6..5ab0b1214 100644 --- a/config/config.toml +++ b/config/config.toml @@ -58,6 +58,10 @@ GetCodeMetadata = 10 IsBuiltinFunction = 10 IsReservedFunctionName = 10 + GetRoundTime = 10 + EpochStartBlockTimeStamp = 10 + EpochStartBlockNonce = 10 + EpochStartBlockRound = 10 [EthAPICost] UseGas = 10 diff --git a/config/gasCost.go b/config/gasCost.go index 5d2d213e5..da0247b3e 100644 --- a/config/gasCost.go +++ b/config/gasCost.go @@ -31,58 +31,62 @@ type BaseOperationCost struct { // BaseOpsAPICost defines the API operations gas cost config structure type BaseOpsAPICost struct { - GetSCAddress uint64 - GetOwnerAddress uint64 - IsSmartContract uint64 - GetShardOfAddress uint64 - GetExternalBalance uint64 - GetBlockHash uint64 - GetOriginalTxHash uint64 - GetCurrentTxHash uint64 - GetPrevTxHash uint64 - TransferValue uint64 - GetArgument uint64 - GetFunction uint64 - GetNumArguments uint64 - StorageStore uint64 - StorageLoad uint64 - CachedStorageLoad uint64 - GetCaller uint64 - GetCallValue uint64 - Log uint64 - Finish uint64 - SignalError uint64 - GetBlockTimeStamp uint64 - GetGasLeft uint64 - Int64GetArgument uint64 - Int64StorageStore uint64 - Int64StorageLoad uint64 - Int64Finish uint64 - GetStateRootHash uint64 - GetBlockNonce uint64 - GetBlockEpoch uint64 - GetBlockRound uint64 - GetBlockRandomSeed uint64 - ExecuteOnSameContext uint64 - ExecuteOnDestContext uint64 - DelegateExecution uint64 - ExecuteReadOnly uint64 - AsyncCallStep uint64 - AsyncCallbackGasLock uint64 - CreateAsyncCall uint64 - SetAsyncCallback uint64 - SetAsyncGroupCallback uint64 - SetAsyncContextCallback uint64 - GetCallbackClosure uint64 - CreateContract uint64 - GetReturnData uint64 - GetNumReturnData uint64 - GetReturnDataSize uint64 - CleanReturnData uint64 - DeleteFromReturnData uint64 - GetCodeMetadata uint64 - IsBuiltinFunction uint64 - IsReservedFunctionName uint64 + GetSCAddress uint64 + GetOwnerAddress uint64 + IsSmartContract uint64 + GetShardOfAddress uint64 + GetExternalBalance uint64 + GetBlockHash uint64 + GetOriginalTxHash uint64 + GetCurrentTxHash uint64 + GetPrevTxHash uint64 + TransferValue uint64 + GetArgument uint64 + GetFunction uint64 + GetNumArguments uint64 + StorageStore uint64 + StorageLoad uint64 + CachedStorageLoad uint64 + GetCaller uint64 + GetCallValue uint64 + Log uint64 + Finish uint64 + SignalError uint64 + GetBlockTimeStamp uint64 + GetGasLeft uint64 + Int64GetArgument uint64 + Int64StorageStore uint64 + Int64StorageLoad uint64 + Int64Finish uint64 + GetStateRootHash uint64 + GetBlockNonce uint64 + GetBlockEpoch uint64 + GetBlockRound uint64 + GetBlockRandomSeed uint64 + ExecuteOnSameContext uint64 + ExecuteOnDestContext uint64 + DelegateExecution uint64 + ExecuteReadOnly uint64 + AsyncCallStep uint64 + AsyncCallbackGasLock uint64 + CreateAsyncCall uint64 + SetAsyncCallback uint64 + SetAsyncGroupCallback uint64 + SetAsyncContextCallback uint64 + GetCallbackClosure uint64 + CreateContract uint64 + GetReturnData uint64 + GetNumReturnData uint64 + GetReturnDataSize uint64 + CleanReturnData uint64 + DeleteFromReturnData uint64 + GetCodeMetadata uint64 + IsBuiltinFunction uint64 + IsReservedFunctionName uint64 + GetRoundTime uint64 + EpochStartBlockTimeStamp uint64 + EpochStartBlockNonce uint64 + EpochStartBlockRound uint64 } // DynamicStorageLoadCostCoefficients holds the signed coefficients of the func that will compute the gas cost diff --git a/config/gasSchedule.go b/config/gasSchedule.go index 60ef83c3b..96ec76762 100644 --- a/config/gasSchedule.go +++ b/config/gasSchedule.go @@ -314,6 +314,10 @@ func FillGasMapBaseOpsAPICosts(value, asyncCallbackGasLock uint64) map[string]ui gasMap["GetCodeMetadata"] = value gasMap["IsBuiltinFunction"] = value gasMap["IsReservedFunctionName"] = value + gasMap["GetRoundTime"] = value + gasMap["EpochStartBlockTimeStamp"] = value + gasMap["EpochStartBlockNonce"] = value + gasMap["EpochStartBlockRound"] = value return gasMap } diff --git a/executor/vmHooks.go b/executor/vmHooks.go index c32d718a3..b8c6e3e1b 100644 --- a/executor/vmHooks.go +++ b/executor/vmHooks.go @@ -86,6 +86,10 @@ type MainVMHooks interface { GetPrevBlockRound() int64 GetPrevBlockEpoch() int64 GetPrevBlockRandomSeed(pointer MemPtr) + GetRoundTime() int64 + EpochStartBlockTimeStamp() int64 + EpochStartBlockNonce() int64 + EpochStartBlockRound() int64 Finish(pointer MemPtr, length MemLength) ExecuteOnSameContext(gasLimit int64, addressOffset MemPtr, valueOffset MemPtr, functionOffset MemPtr, functionLength MemLength, numArguments int32, argumentsLengthOffset MemPtr, dataOffset MemPtr) int32 ExecuteOnDestContext(gasLimit int64, addressOffset MemPtr, valueOffset MemPtr, functionOffset MemPtr, functionLength MemLength, numArguments int32, argumentsLengthOffset MemPtr, dataOffset MemPtr) int32 diff --git a/executor/wrapper/wrapperVMHooks.go b/executor/wrapper/wrapperVMHooks.go index a5e57419c..cda45b313 100644 --- a/executor/wrapper/wrapperVMHooks.go +++ b/executor/wrapper/wrapperVMHooks.go @@ -606,6 +606,42 @@ func (w *WrapperVMHooks) GetPrevBlockRandomSeed(pointer executor.MemPtr) { w.logger.LogVMHookCallAfter(callInfo) } +// GetRoundTime VM hook wrapper +func (w *WrapperVMHooks) GetRoundTime() int64 { + callInfo := "GetRoundTime()" + w.logger.LogVMHookCallBefore(callInfo) + result := w.wrappedVMHooks.GetRoundTime() + w.logger.LogVMHookCallAfter(callInfo) + return result +} + +// EpochStartBlockTimeStamp VM hook wrapper +func (w *WrapperVMHooks) EpochStartBlockTimeStamp() int64 { + callInfo := "EpochStartBlockTimeStamp()" + w.logger.LogVMHookCallBefore(callInfo) + result := w.wrappedVMHooks.EpochStartBlockTimeStamp() + w.logger.LogVMHookCallAfter(callInfo) + return result +} + +// EpochStartBlockNonce VM hook wrapper +func (w *WrapperVMHooks) EpochStartBlockNonce() int64 { + callInfo := "EpochStartBlockNonce()" + w.logger.LogVMHookCallBefore(callInfo) + result := w.wrappedVMHooks.EpochStartBlockNonce() + w.logger.LogVMHookCallAfter(callInfo) + return result +} + +// EpochStartBlockRound VM hook wrapper +func (w *WrapperVMHooks) EpochStartBlockRound() int64 { + callInfo := "EpochStartBlockRound()" + w.logger.LogVMHookCallBefore(callInfo) + result := w.wrappedVMHooks.EpochStartBlockRound() + w.logger.LogVMHookCallAfter(callInfo) + return result +} + // Finish VM hook wrapper func (w *WrapperVMHooks) Finish(pointer executor.MemPtr, length executor.MemLength) { callInfo := fmt.Sprintf("Finish(%d, %d)", pointer, length) diff --git a/go.mod b/go.mod index 577d833a7..2b9a0b8bd 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,12 @@ 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.21-0.20240725065431-6e9bfee5a4c6 + github.com/multiversx/mx-chain-core-go v1.2.22 github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240725071000-c3212540166f - github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240725065747-176bd697c775 - github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240725072925-89c927c8b6a6 + github.com/multiversx/mx-chain-logger-go v1.0.15 + github.com/multiversx/mx-chain-scenario-go v1.4.5-0.20240802080531-0906745c04b2 github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240725070753-aa7fb322ebdf - github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240725072715-8806f1301087 + github.com/multiversx/mx-chain-vm-common-go v1.5.17-0.20241021074004-c2bdb78da54a 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 2ab212384..b89e8efa0 100644 --- a/go.sum +++ b/go.sum @@ -83,18 +83,18 @@ 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.21-0.20240725065431-6e9bfee5a4c6 h1:Q7uUjTYTrt8Mw9oq5JWPv+WHhpxHTv6lhZZlhPuNcoQ= -github.com/multiversx/mx-chain-core-go v1.2.21-0.20240725065431-6e9bfee5a4c6/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.22 h1:yDYrvoQOBbsDerEp7L3+de5AfMy3pTF333gWPpd+FNk= +github.com/multiversx/mx-chain-core-go v1.2.22/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240725071000-c3212540166f h1:jydjrmVFvSllBOTppveOAkLITpOYKk0kma5z0bfDImI= github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240725071000-c3212540166f/go.mod h1:9aSp//uBSvqFdzh4gvYISraoruhr1FCTXgPQalQ687k= -github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240725065747-176bd697c775 h1:a8LOfz3p4MQfRtbF00rGDAJiebziwtSfVmBHIaHBDdY= -github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240725065747-176bd697c775/go.mod h1:owPYyrK7RcsLx9eOCAZQ22fIyW6BE7ttJr4XIhFIbQw= -github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240725072925-89c927c8b6a6 h1:QGQjSlPix5nBtCkcdyKo0b2sRYXwYF/GBtccOqDbU6Y= -github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240725072925-89c927c8b6a6/go.mod h1:MvJiMtuyGq43aS9eOgF+xQUWk0hYxvCQqLrT77bhBaE= +github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= +github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= +github.com/multiversx/mx-chain-scenario-go v1.4.5-0.20240802080531-0906745c04b2 h1:7/4jvB5DBQqKL4udY4RjcwHZ7sRH20fXM3Nj830Rv84= +github.com/multiversx/mx-chain-scenario-go v1.4.5-0.20240802080531-0906745c04b2/go.mod h1:5lkUsHiCCX1rJOx0d763OIlD85y85xCYU0Zlzasq6OM= github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240725070753-aa7fb322ebdf h1:L9K7Xzq5SZz6k55R7HrafiRcU+c8/PqozJxys65G4bI= github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240725070753-aa7fb322ebdf/go.mod h1:ptvW/8r6bam55mVpeVZbyvvvydYM0DQwcPOH0W4Xyx8= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240725072715-8806f1301087 h1:ovxs8X50iBL9TOkn0qHrkuXrBS1Y/EWfQOYmFEaXRNs= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240725072715-8806f1301087/go.mod h1:nNGN+rdLRN8Nd6OhFGrkEZS5Ipj5IQCvFT0L/iQbOpU= +github.com/multiversx/mx-chain-vm-common-go v1.5.17-0.20241021074004-c2bdb78da54a h1:+D5GR9SkHTkKU6fIMZLdSQHeIzbDzOT6fSJfKBG80+g= +github.com/multiversx/mx-chain-vm-common-go v1.5.17-0.20241021074004-c2bdb78da54a/go.mod h1:1rSkXreUZNXyPTTdhj47M+Fy62yjxbu3aAsXEtKN3UY= 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/mock/context/blockChainHookStub.go b/mock/context/blockChainHookStub.go index 11f9794f6..118008103 100644 --- a/mock/context/blockChainHookStub.go +++ b/mock/context/blockChainHookStub.go @@ -11,20 +11,25 @@ var _ vmcommon.BlockchainHook = (*BlockchainHookStub)(nil) // BlockchainHookStub is used in tests to check that interface methods were called type BlockchainHookStub struct { - NewAddressCalled func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) - GetStorageDataCalled func(accountsAddress []byte, index []byte) ([]byte, uint32, error) - GetBlockHashCalled func(nonce uint64) ([]byte, error) - LastNonceCalled func() uint64 - LastRoundCalled func() uint64 - LastTimeStampCalled func() uint64 - LastRandomSeedCalled func() []byte - LastEpochCalled func() uint32 - GetStateRootHashCalled func() []byte - CurrentNonceCalled func() uint64 - CurrentRoundCalled func() uint64 - CurrentTimeStampCalled func() uint64 - CurrentRandomSeedCalled func() []byte - CurrentEpochCalled func() uint32 + NewAddressCalled func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) + GetStorageDataCalled func(accountsAddress []byte, index []byte) ([]byte, uint32, error) + GetBlockHashCalled func(nonce uint64) ([]byte, error) + LastNonceCalled func() uint64 + LastRoundCalled func() uint64 + LastTimeStampCalled func() uint64 + LastRandomSeedCalled func() []byte + LastEpochCalled func() uint32 + GetStateRootHashCalled func() []byte + CurrentNonceCalled func() uint64 + CurrentRoundCalled func() uint64 + CurrentTimeStampCalled func() uint64 + CurrentRandomSeedCalled func() []byte + CurrentEpochCalled func() uint32 + RoundTimeCalled func() uint64 + EpochStartBlockTimeStampCalled func() uint64 + EpochStartBlockNonceCalled func() uint64 + EpochStartBlockRoundCalled func() uint64 + ProcessBuiltInFunctionCalled func(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error) GetBuiltinFunctionNamesCalled func() vmcommon.FunctionNames GetAllStateCalled func(address []byte) (map[string][]byte, error) @@ -153,6 +158,38 @@ func (b *BlockchainHookStub) CurrentEpoch() uint32 { return 0 } +// RoundTime mocked method +func (b *BlockchainHookStub) RoundTime() uint64 { + if b.RoundTimeCalled != nil { + return b.RoundTimeCalled() + } + return 0 +} + +// EpochStartBlockTimeStamp mocked method +func (b *BlockchainHookStub) EpochStartBlockTimeStamp() uint64 { + if b.EpochStartBlockTimeStampCalled != nil { + return b.EpochStartBlockTimeStampCalled() + } + return 0 +} + +// EpochStartBlockNonce mocked method +func (b *BlockchainHookStub) EpochStartBlockNonce() uint64 { + if b.EpochStartBlockNonceCalled != nil { + return b.EpochStartBlockNonceCalled() + } + return 0 +} + +// EpochStartBlockRound VMHooks implementation. +func (b *BlockchainHookStub) EpochStartBlockRound() uint64 { + if b.EpochStartBlockRoundCalled != nil { + return b.EpochStartBlockRoundCalled() + } + return 0 +} + // ProcessBuiltInFunction mocked method func (b *BlockchainHookStub) ProcessBuiltInFunction(input *vmcommon.ContractCallInput) (*vmcommon.VMOutput, error) { if b.ProcessBuiltInFunctionCalled != nil { diff --git a/mock/context/executorMockFunc.go b/mock/context/executorMockFunc.go index d606a3170..f4995e81a 100644 --- a/mock/context/executorMockFunc.go +++ b/mock/context/executorMockFunc.go @@ -76,6 +76,10 @@ var functionNames = map[string]struct{}{ "getPrevBlockRound": empty, "getPrevBlockEpoch": empty, "getPrevBlockRandomSeed": empty, + "getRoundTime": empty, + "epochStartBlockTimeStamp": empty, + "epochStartBlockNonce": empty, + "epochStartBlockRound": empty, "finish": empty, "executeOnSameContext": empty, "executeOnDestContext": empty, diff --git a/scenario/gasSchedules/gasScheduleEmbedGenerated.go b/scenario/gasSchedules/gasScheduleEmbedGenerated.go index c6e7874af..a60d8ac52 100644 --- a/scenario/gasSchedules/gasScheduleEmbedGenerated.go +++ b/scenario/gasSchedules/gasScheduleEmbedGenerated.go @@ -122,6 +122,10 @@ const ( GetCodeMetadata = 100 IsBuiltinFunction = 100 IsReservedFunctionName = 100 + GetRoundTime = 100 + EpochStartBlockTimeStamp = 100 + EpochStartBlockNonce = 100 + EpochStartBlockRound = 100 [EthAPICost] UseGas = 100 @@ -957,6 +961,10 @@ const ( GetCodeMetadata = 100 IsBuiltinFunction = 100 IsReservedFunctionName = 100 + GetRoundTime = 100 + EpochStartBlockTimeStamp = 100 + EpochStartBlockNonce = 100 + EpochStartBlockRound = 100 [EthAPICost] UseGas = 100 diff --git a/scenario/gasSchedules/gasScheduleV3.toml b/scenario/gasSchedules/gasScheduleV3.toml index e037639a0..193ee0517 100644 --- a/scenario/gasSchedules/gasScheduleV3.toml +++ b/scenario/gasSchedules/gasScheduleV3.toml @@ -110,6 +110,10 @@ GetCodeMetadata = 100 IsBuiltinFunction = 100 IsReservedFunctionName = 100 + GetRoundTime = 10000 + EpochStartBlockTimeStamp = 10000 + EpochStartBlockNonce = 10000 + EpochStartBlockRound = 10000 [EthAPICost] UseGas = 100 diff --git a/scenario/gasSchedules/gasScheduleV4.toml b/scenario/gasSchedules/gasScheduleV4.toml index de9937dd7..8a5b21796 100644 --- a/scenario/gasSchedules/gasScheduleV4.toml +++ b/scenario/gasSchedules/gasScheduleV4.toml @@ -112,6 +112,10 @@ GetCodeMetadata = 100 IsBuiltinFunction = 100 IsReservedFunctionName = 100 + GetRoundTime = 10000 + EpochStartBlockTimeStamp = 10000 + EpochStartBlockNonce = 10000 + EpochStartBlockRound = 10000 [EthAPICost] UseGas = 100 diff --git a/test/contracts/new-blockchain-hooks/Makefile b/test/contracts/new-blockchain-hooks/Makefile new file mode 100644 index 000000000..8ac5eed31 --- /dev/null +++ b/test/contracts/new-blockchain-hooks/Makefile @@ -0,0 +1,2 @@ +build: + rustc --target wasm32-unknown-unknown -O --crate-type=cdylib src/lib.rs -o output/new-blockchain-hooks.wasm \ No newline at end of file diff --git a/test/contracts/new-blockchain-hooks/output/new-blockchain-hooks.wasm b/test/contracts/new-blockchain-hooks/output/new-blockchain-hooks.wasm new file mode 100755 index 000000000..9fc969f4b Binary files /dev/null and b/test/contracts/new-blockchain-hooks/output/new-blockchain-hooks.wasm differ diff --git a/test/contracts/new-blockchain-hooks/src/lib.rs b/test/contracts/new-blockchain-hooks/src/lib.rs new file mode 100644 index 000000000..e980ffa6b --- /dev/null +++ b/test/contracts/new-blockchain-hooks/src/lib.rs @@ -0,0 +1,51 @@ +#![no_std] +#![no_main] + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +pub extern "C" fn test_round_time() { + unsafe { + let result = getRoundTime(); + let result: [u8; 1] = [(result & 0xff) as u8]; + finish(result.as_ref().as_ptr(), 1); + }; +} + +#[no_mangle] +pub extern "C" fn test_epoch_start_block_time_stamp() { + unsafe { + let result = epochStartBlockTimeStamp(); + let result: [u8; 1] = [(result & 0xff) as u8]; + finish(result.as_ref().as_ptr(), 1); + }; +} + +#[no_mangle] +pub extern "C" fn test_epoch_start_block_nonce() { + unsafe { + let result = epochStartBlockNonce(); + let result: [u8; 1] = [(result & 0xff) as u8]; + finish(result.as_ref().as_ptr(), 1); + }; +} + +#[no_mangle] +pub extern "C" fn test_epoch_start_block_round() { + unsafe { + let result = epochStartBlockRound(); + let result: [u8; 1] = [(result & 0xff) as u8]; + finish(result.as_ref().as_ptr(), 1); + }; +} + +extern { + fn finish(data: *const u8, len: i32); + fn getRoundTime() -> i64; + fn epochStartBlockTimeStamp() -> i64; + fn epochStartBlockNonce() -> i64; + fn epochStartBlockRound() -> i64; +} \ No newline at end of file diff --git a/vmhost/contexts/blockchain.go b/vmhost/contexts/blockchain.go index 28609e75c..d12a06be3 100644 --- a/vmhost/contexts/blockchain.go +++ b/vmhost/contexts/blockchain.go @@ -247,6 +247,26 @@ func (context *blockchainContext) CurrentRandomSeed() []byte { return context.blockChainHook.CurrentRandomSeed() } +// RoundTime returns the duruation of a round +func (context *blockchainContext) RoundTime() uint64 { + return context.blockChainHook.RoundTime() +} + +// EpochStartBlockTimeStamp returns the timestamp of the first block of the current epoch. +func (context *blockchainContext) EpochStartBlockTimeStamp() uint64 { + return context.blockChainHook.EpochStartBlockTimeStamp() +} + +// EpochStartBlockNonce returns the nonce of the first block of the current epoch. +func (context *blockchainContext) EpochStartBlockNonce() uint64 { + return context.blockChainHook.EpochStartBlockNonce() +} + +// EpochStartBlockRound returns the round of the first block of the current epoch. +func (context *blockchainContext) EpochStartBlockRound() uint64 { + return context.blockChainHook.EpochStartBlockRound() +} + // GetOwnerAddress returns the owner address of the contract being executed. func (context *blockchainContext) GetOwnerAddress() ([]byte, error) { scAddress := context.host.Runtime().GetContextAddress() diff --git a/vmhost/hosttest/newBloclchainHooks_test.go b/vmhost/hosttest/newBloclchainHooks_test.go new file mode 100644 index 000000000..aa3b21b67 --- /dev/null +++ b/vmhost/hosttest/newBloclchainHooks_test.go @@ -0,0 +1,131 @@ +package hostCoretest + +import ( + "math/big" + "testing" + + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-go/testcommon" + + "github.com/stretchr/testify/require" +) + +func TestNewBlockchainHooks_GetRoundTime(t *testing.T) { + code := testcommon.GetTestSCCode("new-blockchain-hooks", "../../") + + blockchainHook := testcommon.BlockchainHookStubForCall(code, nil) + blockchainHook.RoundTimeCalled = func() uint64 { + return 32 + } + + host := testcommon.NewTestHostBuilder(t). + WithBlockchainHook(blockchainHook). + Build() + defer func() { + host.Reset() + }() + + input := testcommon.DefaultTestContractCallInput() + input.GasProvided = 100000 + input.Function = "test_round_time" + input.CallValue = big.NewInt(64) + + vmOutput, err := host.RunSmartContractCall(input) + require.Nil(t, err) + + require.Equal(t, vmcommon.Ok, vmOutput.ReturnCode) + require.Len(t, vmOutput.ReturnData, 1) + require.Equal(t, "", vmOutput.ReturnMessage) + + require.Equal(t, []byte{32}, vmOutput.ReturnData[0]) +} + +func TestNewBlockchainHooks_EpochStartBlockTimeStamp(t *testing.T) { + code := testcommon.GetTestSCCode("new-blockchain-hooks", "../../") + + blockchainHook := testcommon.BlockchainHookStubForCall(code, nil) + blockchainHook.EpochStartBlockTimeStampCalled = func() uint64 { + return 31 + } + + host := testcommon.NewTestHostBuilder(t). + WithBlockchainHook(blockchainHook). + Build() + defer func() { + host.Reset() + }() + + input := testcommon.DefaultTestContractCallInput() + input.GasProvided = 100000 + input.Function = "test_epoch_start_block_time_stamp" + input.CallValue = big.NewInt(64) + + vmOutput, err := host.RunSmartContractCall(input) + require.Nil(t, err) + + require.Equal(t, vmcommon.Ok, vmOutput.ReturnCode) + require.Len(t, vmOutput.ReturnData, 1) + require.Equal(t, "", vmOutput.ReturnMessage) + + require.Equal(t, []byte{31}, vmOutput.ReturnData[0]) +} + +func TestNewBlockchainHooks_EpochStartBlockNonce(t *testing.T) { + code := testcommon.GetTestSCCode("new-blockchain-hooks", "../../") + + blockchainHook := testcommon.BlockchainHookStubForCall(code, nil) + blockchainHook.EpochStartBlockNonceCalled = func() uint64 { + return 30 + } + + host := testcommon.NewTestHostBuilder(t). + WithBlockchainHook(blockchainHook). + Build() + defer func() { + host.Reset() + }() + + input := testcommon.DefaultTestContractCallInput() + input.GasProvided = 100000 + input.Function = "test_epoch_start_block_nonce" + input.CallValue = big.NewInt(64) + + vmOutput, err := host.RunSmartContractCall(input) + require.Nil(t, err) + + require.Equal(t, vmcommon.Ok, vmOutput.ReturnCode) + require.Len(t, vmOutput.ReturnData, 1) + require.Equal(t, "", vmOutput.ReturnMessage) + + require.Equal(t, []byte{30}, vmOutput.ReturnData[0]) +} + +func TestNewBlockchainHooks_EpochStartBlockRound(t *testing.T) { + code := testcommon.GetTestSCCode("new-blockchain-hooks", "../../") + + blockchainHook := testcommon.BlockchainHookStubForCall(code, nil) + blockchainHook.EpochStartBlockRoundCalled = func() uint64 { + return 29 + } + + host := testcommon.NewTestHostBuilder(t). + WithBlockchainHook(blockchainHook). + Build() + defer func() { + host.Reset() + }() + + input := testcommon.DefaultTestContractCallInput() + input.GasProvided = 100000 + input.Function = "test_epoch_start_block_round" + input.CallValue = big.NewInt(64) + + vmOutput, err := host.RunSmartContractCall(input) + require.Nil(t, err) + + require.Equal(t, vmcommon.Ok, vmOutput.ReturnCode) + require.Len(t, vmOutput.ReturnData, 1) + require.Equal(t, "", vmOutput.ReturnMessage) + + require.Equal(t, []byte{29}, vmOutput.ReturnData[0]) +} diff --git a/vmhost/interface.go b/vmhost/interface.go index fa74ff916..9d133b595 100644 --- a/vmhost/interface.go +++ b/vmhost/interface.go @@ -84,6 +84,10 @@ type BlockchainContext interface { CurrentNonce() uint64 CurrentTimeStamp() uint64 CurrentRandomSeed() []byte + RoundTime() uint64 + EpochStartBlockTimeStamp() uint64 + EpochStartBlockNonce() uint64 + EpochStartBlockRound() uint64 LastRandomSeed() []byte IncreaseNonce(addr []byte) GetCodeHash(addr []byte) []byte diff --git a/vmhost/mock/blockchainContextMock.go b/vmhost/mock/blockchainContextMock.go index 854958ab7..6017b7de7 100644 --- a/vmhost/mock/blockchainContextMock.go +++ b/vmhost/mock/blockchainContextMock.go @@ -105,6 +105,26 @@ func (b *BlockchainContextMock) CurrentTimeStamp() uint64 { return 0 } +// RoundTime - +func (b *BlockchainContextMock) RoundTime() uint64 { + return 0 +} + +// EpochStartBlockTimeStamp - +func (b *BlockchainContextMock) EpochStartBlockTimeStamp() uint64 { + return 0 +} + +// EpochStartBlockNonce - +func (b *BlockchainContextMock) EpochStartBlockNonce() uint64 { + return 0 +} + +// EpochStartBlockRound - +func (b *BlockchainContextMock) EpochStartBlockRound() uint64 { + return 0 +} + // CurrentRandomSeed - func (b *BlockchainContextMock) CurrentRandomSeed() []byte { return bytes.Repeat([]byte{1}, 32) diff --git a/vmhost/vmhooks/baseOps.go b/vmhost/vmhooks/baseOps.go index 72547da21..7fd5a4c08 100644 --- a/vmhost/vmhooks/baseOps.go +++ b/vmhost/vmhooks/baseOps.go @@ -100,6 +100,10 @@ const ( getOriginalTxHashName = "getOriginalTxHash" getCurrentTxHashName = "getCurrentTxHash" getPrevTxHashName = "getPrevTxHash" + getRoundTimeName = "getRoundTime" + epochStartBlockTimeStampName = "epochStartBlockTimeStamp" + epochStartBlockNonceName = "epochStartBlockNonce" + epochStartBlockRoundName = "epochStartBlockRound" ) type CreateContractCallType int @@ -2909,6 +2913,71 @@ func (context *VMHooksImpl) GetPrevBlockRandomSeed(pointer executor.MemPtr) { } } +// GetRoundTime VMHooks implementation. +// @autogenerate(VMHooks) +func (context *VMHooksImpl) GetRoundTime() int64 { + blockchain := context.GetBlockchainContext() + metering := context.GetMeteringContext() + + gasToUse := metering.GasSchedule().BaseOpsAPICost.GetRoundTime + err := metering.UseGasBoundedAndAddTracedGas(getRoundTimeName, gasToUse) + if err != nil { + context.FailExecution(err) + return -1 + } + + return int64(blockchain.RoundTime()) +} + +// EpochStartBlockTimeStamp VMHooks implementation. +// @autogenerate(VMHooks) +func (context *VMHooksImpl) EpochStartBlockTimeStamp() int64 { + blockchain := context.GetBlockchainContext() + metering := context.GetMeteringContext() + + gasToUse := metering.GasSchedule().BaseOpsAPICost.EpochStartBlockTimeStamp + err := metering.UseGasBoundedAndAddTracedGas(epochStartBlockTimeStampName, gasToUse) + if err != nil { + context.FailExecution(err) + return -1 + } + + return int64(blockchain.EpochStartBlockTimeStamp()) +} + +// EpochStartBlockNonce VMHooks implementation. +// @autogenerate(VMHooks) +func (context *VMHooksImpl) EpochStartBlockNonce() int64 { + blockchain := context.GetBlockchainContext() + metering := context.GetMeteringContext() + + gasToUse := metering.GasSchedule().BaseOpsAPICost.EpochStartBlockNonce + err := metering.UseGasBoundedAndAddTracedGas(epochStartBlockNonceName, gasToUse) + if err != nil { + context.FailExecution(err) + return -1 + } + + return int64(blockchain.EpochStartBlockNonce()) +} + +// EpochStartBlockRound VMHooks implementation. +// @autogenerate(VMHooks) +func (context *VMHooksImpl) EpochStartBlockRound() int64 { + blockchain := context.GetBlockchainContext() + metering := context.GetMeteringContext() + + gasToUse := metering.GasSchedule().BaseOpsAPICost.EpochStartBlockRound + + err := metering.UseGasBoundedAndAddTracedGas(epochStartBlockRoundName, gasToUse) + if err != nil { + context.FailExecution(err) + return -1 + } + + return int64(blockchain.EpochStartBlockRound()) +} + // Finish VMHooks implementation. // @autogenerate(VMHooks) func (context *VMHooksImpl) Finish(pointer executor.MemPtr, length executor.MemLength) { diff --git a/wasmer2/wasmer2ImportsCgo.go b/wasmer2/wasmer2ImportsCgo.go index f85383cba..1eb3e62f2 100644 --- a/wasmer2/wasmer2ImportsCgo.go +++ b/wasmer2/wasmer2ImportsCgo.go @@ -78,6 +78,10 @@ package wasmer2 // extern long long w2_getPrevBlockRound(void* context); // extern long long w2_getPrevBlockEpoch(void* context); // extern void w2_getPrevBlockRandomSeed(void* context, int32_t pointer); +// extern long long w2_getRoundTime(void* context); +// extern long long w2_epochStartBlockTimeStamp(void* context); +// extern long long w2_epochStartBlockNonce(void* context); +// extern long long w2_epochStartBlockRound(void* context); // extern void w2_finish(void* context, int32_t pointer, int32_t length); // extern int32_t w2_executeOnSameContext(void* context, long long gasLimit, int32_t addressOffset, int32_t valueOffset, int32_t functionOffset, int32_t functionLength, int32_t numArguments, int32_t argumentsLengthOffset, int32_t dataOffset); // extern int32_t w2_executeOnDestContext(void* context, long long gasLimit, int32_t addressOffset, int32_t valueOffset, int32_t functionOffset, int32_t functionLength, int32_t numArguments, int32_t argumentsLengthOffset, int32_t dataOffset); @@ -355,6 +359,10 @@ func populateCgoFunctionPointers() *cWasmerVmHookPointers { get_prev_block_round_func_ptr: funcPointer(C.w2_getPrevBlockRound), get_prev_block_epoch_func_ptr: funcPointer(C.w2_getPrevBlockEpoch), get_prev_block_random_seed_func_ptr: funcPointer(C.w2_getPrevBlockRandomSeed), + get_round_time_func_ptr: funcPointer(C.w2_getRoundTime), + epoch_start_block_time_stamp_func_ptr: funcPointer(C.w2_epochStartBlockTimeStamp), + epoch_start_block_nonce_func_ptr: funcPointer(C.w2_epochStartBlockNonce), + epoch_start_block_round_func_ptr: funcPointer(C.w2_epochStartBlockRound), finish_func_ptr: funcPointer(C.w2_finish), execute_on_same_context_func_ptr: funcPointer(C.w2_executeOnSameContext), execute_on_dest_context_func_ptr: funcPointer(C.w2_executeOnDestContext), @@ -959,6 +967,30 @@ func w2_getPrevBlockRandomSeed(context unsafe.Pointer, pointer int32) { vmHooks.GetPrevBlockRandomSeed(executor.MemPtr(pointer)) } +//export w2_getRoundTime +func w2_getRoundTime(context unsafe.Pointer) int64 { + vmHooks := getVMHooksFromContextRawPtr(context) + return vmHooks.GetRoundTime() +} + +//export w2_epochStartBlockTimeStamp +func w2_epochStartBlockTimeStamp(context unsafe.Pointer) int64 { + vmHooks := getVMHooksFromContextRawPtr(context) + return vmHooks.EpochStartBlockTimeStamp() +} + +//export w2_epochStartBlockNonce +func w2_epochStartBlockNonce(context unsafe.Pointer) int64 { + vmHooks := getVMHooksFromContextRawPtr(context) + return vmHooks.EpochStartBlockNonce() +} + +//export w2_epochStartBlockRound +func w2_epochStartBlockRound(context unsafe.Pointer) int64 { + vmHooks := getVMHooksFromContextRawPtr(context) + return vmHooks.EpochStartBlockRound() +} + //export w2_finish func w2_finish(context unsafe.Pointer, pointer int32, length int32) { vmHooks := getVMHooksFromContextRawPtr(context) diff --git a/wasmer2/wasmer2Names.go b/wasmer2/wasmer2Names.go index ad662058b..88c80b070 100644 --- a/wasmer2/wasmer2Names.go +++ b/wasmer2/wasmer2Names.go @@ -76,6 +76,10 @@ var functionNames = map[string]struct{}{ "getPrevBlockRound": empty, "getPrevBlockEpoch": empty, "getPrevBlockRandomSeed": empty, + "getRoundTime": empty, + "epochStartBlockTimeStamp": empty, + "epochStartBlockNonce": empty, + "epochStartBlockRound": empty, "finish": empty, "executeOnSameContext": empty, "executeOnDestContext": empty,