diff --git a/runtime/common/computationkind.go b/runtime/common/computationkind.go index 90b96e858e..68be5b6f9b 100644 --- a/runtime/common/computationkind.go +++ b/runtime/common/computationkind.go @@ -133,7 +133,7 @@ const ( // ComputationKindSTDLIBPanic ComputationKindSTDLIBAssert - ComputationKindSTDLIBUnsafeRandom + ComputationKindSTDLIBRevertibleRandom _ _ _ diff --git a/runtime/common/computationkind_string.go b/runtime/common/computationkind_string.go index 9ed621d72f..302fdd11bb 100644 --- a/runtime/common/computationkind_string.go +++ b/runtime/common/computationkind_string.go @@ -24,7 +24,7 @@ func _() { _ = x[ComputationKindEncodeValue-1080] _ = x[ComputationKindSTDLIBPanic-1100] _ = x[ComputationKindSTDLIBAssert-1101] - _ = x[ComputationKindSTDLIBUnsafeRandom-1102] + _ = x[ComputationKindSTDLIBRevertibleRandom-1102] _ = x[ComputationKindSTDLIBRLPDecodeString-1108] _ = x[ComputationKindSTDLIBRLPDecodeList-1109] } @@ -36,7 +36,7 @@ const ( _ComputationKind_name_3 = "CreateArrayValueTransferArrayValueDestroyArrayValue" _ComputationKind_name_4 = "CreateDictionaryValueTransferDictionaryValueDestroyDictionaryValue" _ComputationKind_name_5 = "EncodeValue" - _ComputationKind_name_6 = "STDLIBPanicSTDLIBAssertSTDLIBUnsafeRandom" + _ComputationKind_name_6 = "STDLIBPanicSTDLIBAssertSTDLIBRevertibleRandom" _ComputationKind_name_7 = "STDLIBRLPDecodeStringSTDLIBRLPDecodeList" ) @@ -45,7 +45,7 @@ var ( _ComputationKind_index_2 = [...]uint8{0, 20, 42, 63} _ComputationKind_index_3 = [...]uint8{0, 16, 34, 51} _ComputationKind_index_4 = [...]uint8{0, 21, 44, 66} - _ComputationKind_index_6 = [...]uint8{0, 11, 23, 41} + _ComputationKind_index_6 = [...]uint8{0, 11, 23, 45} _ComputationKind_index_7 = [...]uint8{0, 21, 40} ) diff --git a/runtime/environment.go b/runtime/environment.go index 426f38dcfe..2d837c386d 100644 --- a/runtime/environment.go +++ b/runtime/environment.go @@ -126,7 +126,7 @@ type interpreterEnvironment struct { var _ Environment = &interpreterEnvironment{} var _ stdlib.Logger = &interpreterEnvironment{} -var _ stdlib.UnsafeRandomGenerator = &interpreterEnvironment{} +var _ stdlib.RandomGenerator = &interpreterEnvironment{} var _ stdlib.BlockAtHeightProvider = &interpreterEnvironment{} var _ stdlib.CurrentBlockProvider = &interpreterEnvironment{} var _ stdlib.PublicAccountHandler = &interpreterEnvironment{} diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index 8f1af02fb3..f19f19b04d 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -4734,7 +4734,7 @@ func TestRuntimeBlock(t *testing.T) { ) } -func TestRuntimeUnsafeRandom(t *testing.T) { +func TestRuntimeRandom(t *testing.T) { t.Parallel() @@ -4743,8 +4743,10 @@ func TestRuntimeUnsafeRandom(t *testing.T) { script := []byte(` transaction { prepare() { - let rand = unsafeRandom() - log(rand) + let rand1 = revertibleRandom() + log(rand1) + let rand2 = unsafeRandom() + log(rand2) } } `) @@ -4777,6 +4779,7 @@ func TestRuntimeUnsafeRandom(t *testing.T) { assert.Equal(t, []string{ "7558174677681708339", + "7558174677681708339", }, loggedMessages, ) diff --git a/runtime/stdlib/builtin.go b/runtime/stdlib/builtin.go index 60e0111fc2..3ec0e2474a 100644 --- a/runtime/stdlib/builtin.go +++ b/runtime/stdlib/builtin.go @@ -20,7 +20,7 @@ package stdlib type StandardLibraryHandler interface { Logger - UnsafeRandomGenerator + RandomGenerator BlockAtHeightProvider CurrentBlockProvider PublicAccountHandler @@ -40,6 +40,7 @@ func DefaultStandardLibraryValues(handler StandardLibraryHandler) []StandardLibr SignatureAlgorithmConstructor, RLPContract, NewLogFunction(handler), + NewRevertibleRandomFunction(handler), NewUnsafeRandomFunction(handler), NewGetBlockFunction(handler), NewGetCurrentBlockFunction(handler), diff --git a/runtime/stdlib/random.go b/runtime/stdlib/random.go index 558d87f023..ffc28172fd 100644 --- a/runtime/stdlib/random.go +++ b/runtime/stdlib/random.go @@ -26,7 +26,7 @@ import ( "github.com/onflow/cadence/runtime/sema" ) -const unsafeRandomFunctionDocString = ` +const revertibleRandomFunctionDocString = ` Returns a pseudo-random number. NOTE: The use of this function is unsafe if not used correctly. @@ -34,18 +34,56 @@ NOTE: The use of this function is unsafe if not used correctly. Follow best practices to prevent security issues when using this function ` -var unsafeRandomFunctionType = &sema.FunctionType{ +var revertibleRandomFunctionType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation( sema.UInt64Type, ), } -type UnsafeRandomGenerator interface { +type RandomGenerator interface { // ReadRandom reads pseudo-random bytes into the input slice, using distributed randomness. ReadRandom([]byte) error } -func NewUnsafeRandomFunction(generator UnsafeRandomGenerator) StandardLibraryValue { +func NewRevertibleRandomFunction(generator RandomGenerator) StandardLibraryValue { + return NewStandardLibraryFunction( + "revertibleRandom", + revertibleRandomFunctionType, + revertibleRandomFunctionDocString, + func(invocation interpreter.Invocation) interpreter.Value { + return interpreter.NewUInt64Value( + invocation.Interpreter, + func() uint64 { + var buffer [8]byte + var err error + errors.WrapPanic(func() { + err = generator.ReadRandom(buffer[:]) + }) + if err != nil { + panic(interpreter.WrappedExternalError(err)) + } + return binary.LittleEndian.Uint64(buffer[:]) + }, + ) + }, + ) +} + +// `unsafeRandom` related constants and functions will be deleted +// when the function is deprecated +const unsafeRandomFunctionDocString = ` +Deprecated: Use revertibleRandom instead. + +Returns a pseudo-random number. + +NOTE: The use of this function is unsafe if not used correctly. + +Follow best practices to prevent security issues when using this function +` + +var unsafeRandomFunctionType = revertibleRandomFunctionType + +func NewUnsafeRandomFunction(generator RandomGenerator) StandardLibraryValue { return NewStandardLibraryFunction( "unsafeRandom", unsafeRandomFunctionType,