|
| 1 | +package config |
| 2 | + |
| 3 | +import ( |
| 4 | + "time" |
| 5 | + |
| 6 | + "github.com/smartcontractkit/chainlink-common/pkg/config" |
| 7 | + |
| 8 | + "github.com/smartcontractkit/chainlink-framework/multinode" |
| 9 | +) |
| 10 | + |
| 11 | +// MultiNodeConfig is a wrapper to provide required functions while keeping configs Public |
| 12 | +type MultiNodeConfig struct { |
| 13 | + MultiNode |
| 14 | +} |
| 15 | + |
| 16 | +type MultiNode struct { |
| 17 | + // Feature flag |
| 18 | + Enabled *bool |
| 19 | + |
| 20 | + // Node Configs |
| 21 | + PollFailureThreshold *uint32 |
| 22 | + PollInterval *config.Duration |
| 23 | + SelectionMode *string |
| 24 | + SyncThreshold *uint32 |
| 25 | + NodeIsSyncingEnabled *bool |
| 26 | + LeaseDuration *config.Duration |
| 27 | + FinalizedBlockPollInterval *config.Duration |
| 28 | + EnforceRepeatableRead *bool |
| 29 | + DeathDeclarationDelay *config.Duration |
| 30 | + |
| 31 | + // Chain Configs |
| 32 | + NodeNoNewHeadsThreshold *config.Duration |
| 33 | + NoNewFinalizedHeadsThreshold *config.Duration |
| 34 | + FinalityDepth *uint32 |
| 35 | + FinalityTagEnabled *bool |
| 36 | + FinalizedBlockOffset *uint32 |
| 37 | +} |
| 38 | + |
| 39 | +func (c *MultiNodeConfig) Enabled() bool { |
| 40 | + return c.MultiNode.Enabled != nil && *c.MultiNode.Enabled |
| 41 | +} |
| 42 | + |
| 43 | +func (c *MultiNodeConfig) PollFailureThreshold() uint32 { |
| 44 | + return *c.MultiNode.PollFailureThreshold |
| 45 | +} |
| 46 | + |
| 47 | +func (c *MultiNodeConfig) PollInterval() time.Duration { |
| 48 | + return c.MultiNode.PollInterval.Duration() |
| 49 | +} |
| 50 | + |
| 51 | +func (c *MultiNodeConfig) SelectionMode() string { |
| 52 | + return *c.MultiNode.SelectionMode |
| 53 | +} |
| 54 | + |
| 55 | +func (c *MultiNodeConfig) SyncThreshold() uint32 { |
| 56 | + return *c.MultiNode.SyncThreshold |
| 57 | +} |
| 58 | + |
| 59 | +func (c *MultiNodeConfig) NodeIsSyncingEnabled() bool { |
| 60 | + return *c.MultiNode.NodeIsSyncingEnabled |
| 61 | +} |
| 62 | + |
| 63 | +func (c *MultiNodeConfig) LeaseDuration() time.Duration { return c.MultiNode.LeaseDuration.Duration() } |
| 64 | + |
| 65 | +func (c *MultiNodeConfig) FinalizedBlockPollInterval() time.Duration { |
| 66 | + return c.MultiNode.FinalizedBlockPollInterval.Duration() |
| 67 | +} |
| 68 | + |
| 69 | +func (c *MultiNodeConfig) EnforceRepeatableRead() bool { return *c.MultiNode.EnforceRepeatableRead } |
| 70 | + |
| 71 | +func (c *MultiNodeConfig) DeathDeclarationDelay() time.Duration { |
| 72 | + return c.MultiNode.DeathDeclarationDelay.Duration() |
| 73 | +} |
| 74 | + |
| 75 | +func (c *MultiNodeConfig) NodeNoNewHeadsThreshold() time.Duration { |
| 76 | + return c.MultiNode.NodeNoNewHeadsThreshold.Duration() |
| 77 | +} |
| 78 | + |
| 79 | +func (c *MultiNodeConfig) NoNewFinalizedHeadsThreshold() time.Duration { |
| 80 | + return c.MultiNode.NoNewFinalizedHeadsThreshold.Duration() |
| 81 | +} |
| 82 | + |
| 83 | +func (c *MultiNodeConfig) FinalityDepth() uint32 { return *c.MultiNode.FinalityDepth } |
| 84 | + |
| 85 | +func (c *MultiNodeConfig) FinalityTagEnabled() bool { return *c.MultiNode.FinalityTagEnabled } |
| 86 | + |
| 87 | +func (c *MultiNodeConfig) FinalizedBlockOffset() uint32 { return *c.MultiNode.FinalizedBlockOffset } |
| 88 | + |
| 89 | +func (c *MultiNodeConfig) SetDefaults() { |
| 90 | + // MultiNode is disabled as it's not fully implemented yet: BCFR-122 |
| 91 | + if c.MultiNode.Enabled == nil { |
| 92 | + c.MultiNode.Enabled = ptr(false) |
| 93 | + } |
| 94 | + |
| 95 | + /* Node Configs */ |
| 96 | + // Failure threshold for polling set to 5 to tolerate some polling failures before taking action. |
| 97 | + if c.MultiNode.PollFailureThreshold == nil { |
| 98 | + c.MultiNode.PollFailureThreshold = ptr(uint32(5)) |
| 99 | + } |
| 100 | + // Poll interval is set to 15 seconds to ensure timely updates while minimizing resource usage. |
| 101 | + if c.MultiNode.PollInterval == nil { |
| 102 | + c.MultiNode.PollInterval = config.MustNewDuration(15 * time.Second) |
| 103 | + } |
| 104 | + // Selection mode defaults to priority level to enable using node priorities |
| 105 | + if c.MultiNode.SelectionMode == nil { |
| 106 | + c.MultiNode.SelectionMode = ptr(multinode.NodeSelectionModePriorityLevel) |
| 107 | + } |
| 108 | + // The sync threshold is set to 10 to allow for some flexibility in node synchronization before considering it out of sync. |
| 109 | + if c.MultiNode.SyncThreshold == nil { |
| 110 | + c.MultiNode.SyncThreshold = ptr(uint32(10)) |
| 111 | + } |
| 112 | + // Lease duration is set to 1 minute by default to allow node locks for a reasonable amount of time. |
| 113 | + if c.MultiNode.LeaseDuration == nil { |
| 114 | + c.MultiNode.LeaseDuration = config.MustNewDuration(time.Minute) |
| 115 | + } |
| 116 | + // Node syncing is not relevant for Solana and is disabled by default. |
| 117 | + if c.MultiNode.NodeIsSyncingEnabled == nil { |
| 118 | + c.MultiNode.NodeIsSyncingEnabled = ptr(false) |
| 119 | + } |
| 120 | + // The finalized block polling interval is set to 5 seconds to ensure timely updates while minimizing resource usage. |
| 121 | + if c.MultiNode.FinalizedBlockPollInterval == nil { |
| 122 | + c.MultiNode.FinalizedBlockPollInterval = config.MustNewDuration(5 * time.Second) |
| 123 | + } |
| 124 | + // Repeatable read guarantee should be enforced by default. |
| 125 | + if c.MultiNode.EnforceRepeatableRead == nil { |
| 126 | + c.MultiNode.EnforceRepeatableRead = ptr(true) |
| 127 | + } |
| 128 | + // The delay before declaring a node dead is set to 20 seconds to give nodes time to recover from temporary issues. |
| 129 | + if c.MultiNode.DeathDeclarationDelay == nil { |
| 130 | + c.MultiNode.DeathDeclarationDelay = config.MustNewDuration(20 * time.Second) |
| 131 | + } |
| 132 | + |
| 133 | + /* Chain Configs */ |
| 134 | + // Threshold for no new heads is set to 20 seconds, assuming that heads should update at a reasonable pace. |
| 135 | + if c.MultiNode.NodeNoNewHeadsThreshold == nil { |
| 136 | + c.MultiNode.NodeNoNewHeadsThreshold = config.MustNewDuration(20 * time.Second) |
| 137 | + } |
| 138 | + // Similar to heads, finalized heads should be updated within 20 seconds. |
| 139 | + if c.MultiNode.NoNewFinalizedHeadsThreshold == nil { |
| 140 | + c.MultiNode.NoNewFinalizedHeadsThreshold = config.MustNewDuration(20 * time.Second) |
| 141 | + } |
| 142 | + // Finality tags are used in Solana and enabled by default. |
| 143 | + if c.MultiNode.FinalityTagEnabled == nil { |
| 144 | + c.MultiNode.FinalityTagEnabled = ptr(true) |
| 145 | + } |
| 146 | + // Finality depth will not be used since finality tags are enabled. |
| 147 | + if c.MultiNode.FinalityDepth == nil { |
| 148 | + c.MultiNode.FinalityDepth = ptr(uint32(0)) |
| 149 | + } |
| 150 | + // Finalized block offset allows for RPCs to be slightly behind the finalized block. |
| 151 | + if c.MultiNode.FinalizedBlockOffset == nil { |
| 152 | + c.MultiNode.FinalizedBlockOffset = ptr(uint32(50)) |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +func (c *MultiNodeConfig) SetFrom(f *MultiNodeConfig) { |
| 157 | + if f.MultiNode.Enabled != nil { |
| 158 | + c.MultiNode.Enabled = f.MultiNode.Enabled |
| 159 | + } |
| 160 | + |
| 161 | + // Node Configs |
| 162 | + if f.MultiNode.PollFailureThreshold != nil { |
| 163 | + c.MultiNode.PollFailureThreshold = f.MultiNode.PollFailureThreshold |
| 164 | + } |
| 165 | + if f.MultiNode.PollInterval != nil { |
| 166 | + c.MultiNode.PollInterval = f.MultiNode.PollInterval |
| 167 | + } |
| 168 | + if f.MultiNode.SelectionMode != nil { |
| 169 | + c.MultiNode.SelectionMode = f.MultiNode.SelectionMode |
| 170 | + } |
| 171 | + if f.MultiNode.SyncThreshold != nil { |
| 172 | + c.MultiNode.SyncThreshold = f.MultiNode.SyncThreshold |
| 173 | + } |
| 174 | + if f.MultiNode.NodeIsSyncingEnabled != nil { |
| 175 | + c.MultiNode.NodeIsSyncingEnabled = f.MultiNode.NodeIsSyncingEnabled |
| 176 | + } |
| 177 | + if f.MultiNode.LeaseDuration != nil { |
| 178 | + c.MultiNode.LeaseDuration = f.MultiNode.LeaseDuration |
| 179 | + } |
| 180 | + if f.MultiNode.FinalizedBlockPollInterval != nil { |
| 181 | + c.MultiNode.FinalizedBlockPollInterval = f.MultiNode.FinalizedBlockPollInterval |
| 182 | + } |
| 183 | + if f.MultiNode.EnforceRepeatableRead != nil { |
| 184 | + c.MultiNode.EnforceRepeatableRead = f.MultiNode.EnforceRepeatableRead |
| 185 | + } |
| 186 | + if f.MultiNode.DeathDeclarationDelay != nil { |
| 187 | + c.MultiNode.DeathDeclarationDelay = f.MultiNode.DeathDeclarationDelay |
| 188 | + } |
| 189 | + |
| 190 | + // Chain Configs |
| 191 | + if f.MultiNode.NodeNoNewHeadsThreshold != nil { |
| 192 | + c.MultiNode.NodeNoNewHeadsThreshold = f.MultiNode.NodeNoNewHeadsThreshold |
| 193 | + } |
| 194 | + if f.MultiNode.NoNewFinalizedHeadsThreshold != nil { |
| 195 | + c.MultiNode.NoNewFinalizedHeadsThreshold = f.MultiNode.NoNewFinalizedHeadsThreshold |
| 196 | + } |
| 197 | + if f.MultiNode.FinalityDepth != nil { |
| 198 | + c.MultiNode.FinalityDepth = f.MultiNode.FinalityDepth |
| 199 | + } |
| 200 | + if f.MultiNode.FinalityTagEnabled != nil { |
| 201 | + c.MultiNode.FinalityTagEnabled = f.MultiNode.FinalityTagEnabled |
| 202 | + } |
| 203 | + if f.MultiNode.FinalizedBlockOffset != nil { |
| 204 | + c.MultiNode.FinalizedBlockOffset = f.MultiNode.FinalizedBlockOffset |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +func ptr[T any](t T) *T { |
| 209 | + return &t |
| 210 | +} |
0 commit comments