From 2a6ae457798db66a36a961bc8fa14aee0f70b35e Mon Sep 17 00:00:00 2001 From: jinhoonbang Date: Tue, 13 Feb 2024 15:36:50 -0800 Subject: [PATCH] add integration tests for pending simulation block and zero confirmation delay (only v2 plus) and add simulation block option to superscript --- core/scripts/common/vrf/jobs/jobs.go | 12 ++- core/scripts/common/vrf/setup-envs/main.go | 7 ++ .../vrfv2/testnet/v2scripts/super_scripts.go | 11 +++ .../testnet/v2plusscripts/super_scripts.go | 11 +++ core/services/pipeline/task.eth_call_test.go | 4 - .../actions/vrf/vrfv2/vrfv2_steps.go | 1 + .../actions/vrf/vrfv2plus/vrfv2plus_steps.go | 1 + integration-tests/smoke/vrfv2_test.go | 86 ++++++++++++++++++ integration-tests/smoke/vrfv2plus_test.go | 89 +++++++++++++++++++ integration-tests/testconfig/vrfv2/config.go | 5 ++ 10 files changed, 219 insertions(+), 8 deletions(-) diff --git a/core/scripts/common/vrf/jobs/jobs.go b/core/scripts/common/vrf/jobs/jobs.go index 7e304f431be..16f892e75f6 100644 --- a/core/scripts/common/vrf/jobs/jobs.go +++ b/core/scripts/common/vrf/jobs/jobs.go @@ -27,7 +27,8 @@ vrf [type=vrfv2 estimate_gas [type=estimategaslimit to="%s" multiplier="%f" - data="$(vrf.output)"] + data="$(vrf.output)" + block=%s] simulate [type=ethcall from="%s" to="%s" @@ -35,7 +36,8 @@ simulate [type=ethcall gasPrice="$(jobSpec.maxGasPrice)" extractRevertReason=true contract="%s" - data="$(vrf.output)"] + data="$(vrf.output)" + block=%s] decode_log->vrf->estimate_gas->simulate """` @@ -66,7 +68,8 @@ generate_proof [type=vrfv2plus estimate_gas [type=estimategaslimit to="%s" multiplier="%f" - data="$(generate_proof.output)"] + data="$(generate_proof.output)" + block=%s] simulate_fulfillment [type=ethcall from="%s" to="%s" @@ -74,7 +77,8 @@ simulate_fulfillment [type=ethcall gasPrice="$(jobSpec.maxGasPrice)" extractRevertReason=true contract="%s" - data="$(generate_proof.output)"] + data="$(generate_proof.output)" + block=%s] decode_log->generate_proof->estimate_gas->simulate_fulfillment """ ` diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 644ebe3d021..6d0f73c0f18 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -94,6 +94,7 @@ func main() { "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") deployVRFOwner := flag.Bool("deploy-vrfv2-owner", true, "whether to deploy VRF owner contracts") useTestCoordinator := flag.Bool("use-test-coordinator", true, "whether to use test coordinator contract or use the normal one") + simulationBlock := flag.String("simulation-block", "pending", "simulation block can be 'pending' or 'latest'") e := helpers.SetupEnv(false) flag.Parse() @@ -104,6 +105,10 @@ func main() { } fmt.Println("Using VRF Version:", *vrfVersion) + if *simulationBlock != "pending" && *simulationBlock != "latest" { + helpers.PanicErr(fmt.Errorf("simulation block must be 'pending' or 'latest'")) + } + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() @@ -229,6 +234,7 @@ func main() { *deployVRFOwner, coordinatorJobSpecConfig, *useTestCoordinator, + *simulationBlock, ) case "v2plus": coordinatorConfigV2Plus := v2plusscripts.CoordinatorConfigV2Plus{ @@ -263,6 +269,7 @@ func main() { nodesMap, uint64(*maxGasPriceGwei), coordinatorJobSpecConfig, + *simulationBlock, ) } diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 1397274656c..5cfc3f81ce1 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -60,6 +60,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", true, "whether to deploy VRF owner contracts") useTestCoordinator := deployCmd.Bool("use-test-coordinator", true, "whether to use test coordinator") + simulationBlock := deployCmd.String("simulation-block", "pending", "simulation block can be 'pending' or 'latest'") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", constants.FallbackWeiPerUnitLink.String(), "fallback wei/link ratio") @@ -83,6 +84,10 @@ func DeployUniverseViaCLI(e helpers.Environment) { reqsForTier4 := deployCmd.Int64("reqs-for-tier-4", constants.ReqsForTier4, "requests for tier 4") reqsForTier5 := deployCmd.Int64("reqs-for-tier-5", constants.ReqsForTier5, "requests for tier 5") + if *simulationBlock != "pending" && *simulationBlock != "latest" { + helpers.PanicErr(fmt.Errorf("simulation block must be 'pending' or 'latest'")) + } + helpers.ParseArgs( deployCmd, os.Args[2:], ) @@ -162,6 +167,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { *deployVRFOwner, coordinatorJobSpecConfig, *useTestCoordinator, + *simulationBlock, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -181,6 +187,7 @@ func VRFV2DeployUniverse( deployVRFOwner bool, coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, useTestCoordinator bool, + simulationBlock string, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -347,6 +354,7 @@ func VRFV2DeployUniverse( coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -355,6 +363,7 @@ func VRFV2DeployUniverse( }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, + simulationBlock, ) if deployVRFOwner { formattedVrfPrimaryJobSpec = strings.Replace(formattedVrfPrimaryJobSpec, @@ -378,6 +387,7 @@ func VRFV2DeployUniverse( coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -386,6 +396,7 @@ func VRFV2DeployUniverse( }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, + simulationBlock, ) if deployVRFOwner { formattedVrfBackupJobSpec = strings.Replace(formattedVrfBackupJobSpec, diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 327c959f90d..fcea01b71c8 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -487,6 +487,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { estimateGasMultiplier := deployCmd.Float64("estimate-gas-multiplier", 1.1, "") pollPeriod := deployCmd.String("poll-period", "300ms", "") requestTimeout := deployCmd.String("request-timeout", "30m0s", "") + simulationBlock := deployCmd.String("simulation-block", "pending", "simulation block can be 'pending' or 'latest'") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") @@ -517,6 +518,10 @@ func DeployUniverseViaCLI(e helpers.Environment) { } } + if *simulationBlock != "pending" && *simulationBlock != "latest" { + helpers.PanicErr(fmt.Errorf("simulation block must be 'pending' or 'latest'")) + } + fallbackWeiPerUnitLink := decimal.RequireFromString(*fallbackWeiPerUnitLinkString).BigInt() subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() @@ -584,6 +589,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap, uint64(*gasLaneMaxGas), coordinatorJobSpecConfig, + *simulationBlock, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -604,6 +610,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, nodesMap map[string]model.Node, gasLaneMaxGas uint64, coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, + simulationBlock string, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -741,6 +748,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -749,6 +757,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, + simulationBlock, ) formattedVrfV2PlusBackupJobSpec := fmt.Sprintf( @@ -765,6 +774,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier + simulationBlock, func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address @@ -773,6 +783,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, + simulationBlock, ) formattedBHSJobSpec := fmt.Sprintf( diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index e814ee8d07a..e91c1cbba84 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -68,7 +68,6 @@ func TestETHCallTask(t *testing.T) { nil, // inputs func(ethClient *evmclimocks.Client, config *pipelinemocks.Config) { // setupClientMocks contractAddr := common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") - //[]byte("baz quux") ethClient. On("CallContext", mock.Anything, @@ -108,7 +107,6 @@ func TestETHCallTask(t *testing.T) { nil, func(ethClient *evmclimocks.Client, config *pipelinemocks.Config) { // setupClientMocks contractAddr := common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") - //[]byte("baz quux") ethClient. On("CallContext", mock.Anything, @@ -147,7 +145,6 @@ func TestETHCallTask(t *testing.T) { nil, func(ethClient *evmclimocks.Client, config *pipelinemocks.Config) { // setupClientMocks contractAddr := common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") - //[]byte("baz quux") ethClient. On("CallContext", mock.Anything, @@ -187,7 +184,6 @@ func TestETHCallTask(t *testing.T) { func(ethClient *evmclimocks.Client, config *pipelinemocks.Config) { // setupClientMocks contractAddr := common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") fromAddr := common.HexToAddress("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF") - //[]byte("baz quux") ethClient. On("CallContext", mock.Anything, diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go index 900731ea507..39d7133dd46 100644 --- a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go +++ b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go @@ -395,6 +395,7 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Conf BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, + SimulationBlock: vrfv2Config.VRFJobSimulationBlock, VRFOwnerConfig: vrfOwnerConfig, } diff --git a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go index 624d9dfe0d6..a3c6352bf37 100644 --- a/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go @@ -333,6 +333,7 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, vrfv2Conf BatchFulfillmentGasMultiplier: *vrfv2Config.VRFJobBatchFulfillmentGasMultiplier, PollPeriod: vrfv2Config.VRFJobPollPeriod.Duration, RequestTimeout: vrfv2Config.VRFJobRequestTimeout.Duration, + SimulationBlock: vrfv2Config.VRFJobSimulationBlock, VRFOwnerConfig: nil, } diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index c289cd019c1..5d77bbd1a11 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -866,3 +866,89 @@ func TestVRFV2WithBHS(t *testing.T) { require.Equal(t, 0, randomWordsRequestedEvent.Raw.BlockHash.Cmp(randRequestBlockHash)) }) } + +func TestVRFV2PendingBlockSimulation(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") + + config.VRFv2.General.VRFJobSimulationBlock = ptr.Ptr[string]("pending") + useVRFOwner := false + useTestCoordinator := false + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(1). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + numberOfTxKeysToCreate := 1 + vrfv2Contracts, subIDs, vrfv2KeyData, nodesMap, err := vrfv2.SetupVRFV2Environment( + env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, + &config, + useVRFOwner, + useTestCoordinator, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.CoordinatorV2.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.CoordinatorV2) + + jobRunsBeforeTest, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + + // test and assert + randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( + l, + vrfv2Contracts.VRFV2Consumer[0], + vrfv2Contracts.CoordinatorV2, + subID, + vrfv2KeyData, + *config.VRFv2.General.MinimumConfirmations, + *config.VRFv2.General.CallbackGasLimit, + *config.VRFv2.General.NumberOfWords, + *config.VRFv2.General.RandomnessRequestCountPerRequest, + *config.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + config.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + jobRuns, err := nodesMap[vrfcommon.VRF].CLNode.API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + + status, err := vrfv2Contracts.VRFV2Consumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index 701cae9a027..61b539e61c5 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -1140,3 +1140,92 @@ func TestVRFV2PlusWithBHS(t *testing.T) { require.Equal(t, 0, randomWordsRequestedEvent.Raw.BlockHash.Cmp(randRequestBlockHash)) }) } + +func TestVRFv2PlusPendingBlockSimulationAndZeroConfirmationDelays(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } + + // override config with minConf = 0 and use pending block for simulation + config.VRFv2Plus.General.MinimumConfirmations = ptr.Ptr[uint16](0) + config.VRFv2Plus.General.VRFJobSimulationBlock = ptr.Ptr[string]("pending") + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(1). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) + require.NoError(t, err, "error deploying mock ETH/LINK feed") + + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err, "error deploying LINK contract") + + numberOfTxKeysToCreate := 2 + vrfv2PlusContracts, subIDs, vrfv2PlusData, nodesMap, err := vrfv2plus.SetupVRFV2_5Environment( + env, + []vrfcommon.VRFNodeType{vrfcommon.VRF}, + &config, + linkToken, + mockETHLinkFeed, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2_5 env") + + subID := subIDs[0] + + subscription, err := vrfv2PlusContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.CoordinatorV2Plus) + + var isNativeBilling = false + + jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + + l.Info().Uint16("minimumConfirmationDelay", *config.VRFv2Plus.General.MinimumConfirmations).Msg("Minimum Confirmation Delay") + + // test and assert + randomWordsFulfilledEvent, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + vrfv2PlusContracts.VRFV2PlusConsumer[0], + vrfv2PlusContracts.CoordinatorV2Plus, + vrfv2PlusData, + subID, + isNativeBilling, + *config.VRFv2Plus.General.MinimumConfirmations, + *config.VRFv2Plus.General.CallbackGasLimit, + *config.VRFv2Plus.General.NumberOfWords, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + config.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, + l, + ) + require.NoError(t, err, "error requesting randomness and waiting for fulfilment") + + jobRuns, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(nodesMap[vrfcommon.VRF].Job.Data.ID) + require.NoError(t, err, "error reading job runs") + require.Equal(t, len(jobRunsBeforeTest.Data)+1, len(jobRuns.Data)) + + status, err := vrfv2PlusContracts.VRFV2PlusConsumer[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "error getting rand request status") + require.True(t, status.Fulfilled) + l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") +} diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go index dca1319e8d8..c9037b59085 100644 --- a/integration-tests/testconfig/vrfv2/config.go +++ b/integration-tests/testconfig/vrfv2/config.go @@ -240,6 +240,7 @@ type General struct { VRFJobBatchFulfillmentGasMultiplier *float64 `toml:"vrf_job_batch_fulfillment_gas_multiplier"` VRFJobPollPeriod *blockchain.StrDuration `toml:"vrf_job_poll_period"` VRFJobRequestTimeout *blockchain.StrDuration `toml:"vrf_job_request_timeout"` + VRFJobSimulationBlock *string `toml:"vrf_job_simulation_block"` //BHS Job Config BHSJobWaitBlocks *int `toml:"bhs_job_wait_blocks"` @@ -378,5 +379,9 @@ func (c *General) Validate() error { return errors.New("bhs_job_wait_blocks must be set to a non-negative value") } + if c.VRFJobSimulationBlock != nil && (*c.VRFJobSimulationBlock != "latest" && *c.VRFJobSimulationBlock != "pending") { + return errors.New("simulation_block must be nil or \"latest\" or \"pending\"") + } + return nil }