github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/history_random_source_provider.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/flow-go/fvm/errors" 7 "github.com/onflow/flow-go/fvm/storage/state" 8 "github.com/onflow/flow-go/fvm/tracing" 9 "github.com/onflow/flow-go/module/trace" 10 "github.com/onflow/flow-go/state/protocol/prg" 11 ) 12 13 type RandomSourceHistoryProvider interface { 14 // RandomSourceHistory provides a source of entropy that can be 15 // expanded on-chain into randoms (using a pseudo-random generator). 16 // This random source is only destined to the history source core-contract 17 // to implement commit-reveal schemes. 18 // The returned slice should have at least 128 bits of entropy. 19 // The function doesn't error in normal operations, any 20 // error should be treated as an exception. 21 RandomSourceHistory() ([]byte, error) 22 } 23 24 type ParseRestrictedRandomSourceHistoryProvider struct { 25 txnState state.NestedTransactionPreparer 26 impl RandomSourceHistoryProvider 27 } 28 29 func NewParseRestrictedRandomSourceHistoryProvider( 30 txnState state.NestedTransactionPreparer, 31 impl RandomSourceHistoryProvider, 32 ) RandomSourceHistoryProvider { 33 return ParseRestrictedRandomSourceHistoryProvider{ 34 txnState: txnState, 35 impl: impl, 36 } 37 } 38 39 func (p ParseRestrictedRandomSourceHistoryProvider) RandomSourceHistory() ([]byte, error) { 40 return parseRestrict1Ret( 41 p.txnState, 42 trace.FVMEnvRandomSourceHistoryProvider, 43 p.impl.RandomSourceHistory, 44 ) 45 } 46 47 // forbiddenRandomSourceHistoryProvider is a RandomSourceHistoryProvider that always returns an error. 48 // this is the default implementation of RandomSourceHistoryProvider. 49 type forbiddenRandomSourceHistoryProvider struct { 50 } 51 52 func NewForbiddenRandomSourceHistoryProvider() RandomSourceHistoryProvider { 53 return &forbiddenRandomSourceHistoryProvider{} 54 } 55 56 func (b forbiddenRandomSourceHistoryProvider) RandomSourceHistory() ([]byte, error) { 57 return nil, errors.NewOperationNotSupportedError("RandomSourceHistory") 58 } 59 60 type historySourceProvider struct { 61 tracer tracing.TracerSpan 62 meter Meter 63 EntropyProvider 64 } 65 66 // NewRandomSourceHistoryProvider creates a new RandomSourceHistoryProvider. 67 // If randomSourceCallAllowed is true, the returned RandomSourceHistoryProvider will 68 // return a random source from the given EntropyProvider. 69 // If randomSourceCallAllowed is false, the returned RandomSourceHistoryProvider will 70 // always return an error. 71 func NewRandomSourceHistoryProvider( 72 tracer tracing.TracerSpan, 73 meter Meter, 74 entropyProvider EntropyProvider, 75 randomSourceCallAllowed bool, 76 ) RandomSourceHistoryProvider { 77 if randomSourceCallAllowed { 78 return &historySourceProvider{ 79 tracer: tracer, 80 meter: meter, 81 EntropyProvider: entropyProvider, 82 } 83 } 84 85 return NewForbiddenRandomSourceHistoryProvider() 86 } 87 88 const randomSourceHistoryLen = 32 89 90 func (b *historySourceProvider) RandomSourceHistory() ([]byte, error) { 91 defer b.tracer.StartExtensiveTracingChildSpan( 92 trace.FVMEnvRandomSourceHistoryProvider).End() 93 94 err := b.meter.MeterComputation(ComputationKindGetRandomSourceHistory, 1) 95 if err != nil { 96 return nil, fmt.Errorf("get block randomSource failed: %w", err) 97 } 98 99 source, err := b.RandomSource() 100 // `RandomSource` does not error in normal operations. 101 // Any error should be treated as an exception. 102 if err != nil { 103 return nil, errors.NewRandomSourceFailure(fmt.Errorf( 104 "get random source for block randomSource failed: %w", err)) 105 } 106 107 // A method that derives `randomSourceHistoryLen` bytes from `source` must: 108 // - extract and expand the entropy in `source` 109 // - output must be independent than the expanded bytes used for Cadence's `random` function 110 // 111 // The method chosen here is to rely on the same CSPRG used to derive randoms from the source entropy 112 // (but other methods are possible) 113 // - use the state/protocol/prg customizer defined for the execution random source history. 114 // (to ensure independence of seeds, customizer must be different than the one used for Cadence's 115 // `random` in random_generator.go) 116 csprg, err := prg.New(source, prg.ExecutionRandomSourceHistory, nil) 117 if err != nil { 118 return nil, fmt.Errorf("failed to create a PRG from source: %w", err) 119 } 120 121 historySource := make([]byte, randomSourceHistoryLen) 122 csprg.Read(historySource) 123 124 return historySource, nil 125 }