Repository: ObolNetwork/charon

Issue:
Add `targetGasLimit` to the `cluster_definition` to allow the creation of clusters with higher gas targets
# 🎯 Problem to be solved

The community wants to raise the target gas limit. Currently that is not easy to do in Charon. 

# 🛠️ Proposed solution

The challenge here, is trying to coordinate all VCs to sign a higher limit. This is something we attempted early in charon development, and disfavoured over signing a single registration at the point of dkg or key splitting. 

To begin, I suggest we stick to the key splitting/dkg moment, but further more realtime approaches may be considered in future. 

The suggestion is to include a `target_gas_limit` field in a new version of the cluster_definition object. With a default of 36m. This could be overridden with the flag `--target-gas-limit int          The target block gas limit for the cluster (Default: 36000000)` 

This const https://github.com/ObolNetwork/charon/blob/main/core/validatorapi/validatorapi.go#L36 is what should be parameterized. 

- [ ] Approved design doc: *link*
- [ ] Core team consensus on the proposed solution

Describe the solution to be implemented

# 🧪 Tests
- [ ] Tested by new automated unit/integration/smoke tests
- [ ] Manually tested on core team/canary/test clusters
- [ ] Manually tested on local compose simnet

<!-- Optional sections

# 👐 Additional acceptance criteria
List any additional acceptance criteria for this issue to be marked as closed.

# ❌ Out of Scope
If there is anything to highlight as out of scope for this issue, please outline it here.

-->


Discussion:
@KaloyanTanev: Completed by #3456, part of v1.3.0 release.

Solution patch:
diff --git a/app/app.go b/app/app.go
index 9f0374ad..5ea2b65f 100644
--- a/app/app.go
+++ b/app/app.go
@@ -96,6 +96,7 @@ type Config struct {
 	ConsensusProtocol       string
 	Nickname                string
 	BeaconNodeHeaders       []string
+	TargetGasLimit          uint
 
 	TestConfig TestConfig
 }
@@ -491,7 +492,7 @@ func wireCoreWorkflow(ctx context.Context, life *lifecycle.Manager, conf Config,
 
 	dutyDB := dutydb.NewMemDB(deadlinerFunc("dutydb"))
 
-	vapi, err := validatorapi.NewComponent(eth2Cl, allPubSharesByKey, nodeIdx.ShareIdx, feeRecipientFunc, conf.BuilderAPI, seenPubkeys)
+	vapi, err := validatorapi.NewComponent(eth2Cl, allPubSharesByKey, nodeIdx.ShareIdx, feeRecipientFunc, conf.BuilderAPI, uint(cluster.GetTargetGasLimit()), seenPubkeys)
 	if err != nil {
 		return err
 	}
diff --git a/cluster/definition.go b/cluster/definition.go
index 4013a043..b1b0cd5c 100644
--- a/cluster/definition.go
+++ b/cluster/definition.go
@@ -64,14 +64,14 @@ func WithLegacyVAddrs(feeRecipientAddress, withdrawalAddress string) func(*Defin
 // The hashes are also populated accordingly. Note that the hashes need to be recalculated when any field is modified.
 func NewDefinition(name string, numVals int, threshold int, feeRecipientAddresses []string, withdrawalAddresses []string,
 	forkVersionHex string, creator Creator, operators []Operator, depositAmounts []int,
-	consensusProtocol string, random io.Reader, opts ...func(*Definition),
+	consensusProtocol string, targetGasLimit uint, random io.Reader, opts ...func(*Definition),
 ) (Definition, error) {
 	if len(feeRecipientAddresses) != numVals {
 		return Definition{}, errors.New("insufficient fee-recipient addresses")
 	}
 
 	if len(withdrawalAddresses) != numVals {
-		return Definition{}, errors.New("insufficient fee-recipient addresses")
+		return Definition{}, errors.New("insufficient withdrawal addresses")
 	}
 
 	def := Definition{
@@ -86,6 +86,7 @@ func NewDefinition(name string, numVals int, threshold int, feeRecipientAddresse
 		Creator:           creator,
 		DepositAmounts:    deposit.EthsToGweis(depositAmounts),
 		ConsensusProtocol: consensusProtocol,
+		TargetGasLimit:    targetGasLimit,
 	}
 
 	for i := range numVals {
@@ -109,6 +110,14 @@ func NewDefinition(name string, numVals int, threshold int, feeRecipientAddresse
 		return Definition{}, errors.New("the version does not support partial deposits", z.Str("version", def.Version))
 	}
 
+	if def.TargetGasLimit != 0 && !supportTargetGasLimit(def.Version) {
+		return Definition{}, errors.New("the version does not support custom target gas limit", z.Str("version", def.Version))
+	}
+
+	if def.TargetGasLimit == 0 && supportTargetGasLimit(def.Version) {
+		return Definition{}, errors.New("target gas limit should be set", z.Str("version", def.Version))
+	}
+
 	return def.SetDefinitionHashes()
 }
 
@@ -160,8 +169,11 @@ type Definition struct {
 	// ConsensusProtocol is the consensus protocol name preferred by the cluster, e.g. "abft".
 	ConsensusProtocol string `config_hash:"12" definition_hash:"12" json:"consensus_protocol,omitempty" ssz:"ByteList[256]"`
 
+	// TargetGasLimit is the target block gas limit for the cluster.
+	TargetGasLimit uint `config_hash:"13" definition_hash:"13" json:"target_gas_limit" ssz:"uint64"`
+
 	// ConfigHash uniquely identifies a cluster definition excluding operator ENRs and signatures.
-	ConfigHash []byte `json:"config_hash,0xhex" ssz:"Bytes32" config_hash:"-" definition_hash:"13"`
+	ConfigHash []byte `json:"config_hash,0xhex" ssz:"Bytes32" config_hash:"-" definition_hash:"14"`
 
 	// DefinitionHash uniquely identifies a cluster definition including operator ENRs and signatures.
 	DefinitionHash []byte `json:"definition_hash,0xhex" ssz:"Bytes32" config_hash:"-" definition_hash:"-"`
@@ -392,6 +404,8 @@ func (d Definition) MarshalJSON() ([]byte, error) {
 		return marshalDefinitionV1x8(d2)
 	case isAnyVersion(d2.Version, v1_9):
 		return marshalDefinitionV1x9(d2)
+	case isAnyVersion(d2.Version, v1_10):
+		return marshalDefinitionV1x10(d2)
 	default:
 		return nil, errors.New("unsupported version")
 	}
@@ -446,6 +460,11 @@ func (d *Definition) UnmarshalJSON(data []byte) error {
 		if err != nil {
 			return err
 		}
+	case isAnyVersion(version.Version, v1_10):
+		def, err = unmarshalDefinitionV1x10(data)
+		if err != nil {
+			return err
+		}
 	default:
 		return errors.New("unsupported version")
 	}
@@ -648,6 +667,35 @@ func marshalDefinitionV1x9(def Definition) ([]byte, error) {
 	return resp, nil
 }
 
+func marshalDefinitionV1x10(def Definition) ([]byte, error) {
+	resp, err := json.Marshal(definitionJSONv1x10{
+		Name:               def.Name,
+		UUID:               def.UUID,
+		Version:            def.Version,
+		Timestamp:          def.Timestamp,
+		NumValidators:      def.NumValidators,
+		Threshold:          def.Threshold,
+		DKGAlgorithm:       def.DKGAlgorithm,
+		ValidatorAddresses: validatorAddressesToJSON(def.ValidatorAddresses),
+		ForkVersion:        def.ForkVersion,
+		ConfigHash:         def.ConfigHash,
+		DefinitionHash:     def.DefinitionHash,
+		Operators:          operatorsToV1x2orLater(def.Operators),
+		Creator: creatorJSON{
+			Address:         def.Creator.Address,
+			ConfigSignature: def.Creator.ConfigSignature,
+		},
+		DepositAmounts:    def.DepositAmounts,
+		ConsensusProtocol: def.ConsensusProtocol,
+		TargetGasLimit:    def.TargetGasLimit,
+	})
+	if err != nil {
+		return nil, errors.Wrap(err, "marshal definition", z.Str("version", def.Version))
+	}
+
+	return resp, nil
+}
+
 func unmarshalDefinitionV1x0or1(data []byte) (def Definition, err error) {
 	var defJSON definitionJSONv1x0or1
 	if err := json.Unmarshal(data, &defJSON); err != nil {
@@ -847,6 +895,43 @@ func unmarshalDefinitionV1x9(data []byte) (def Definition, err error) {
 	}, nil
 }
 
+func unmarshalDefinitionV1x10(data []byte) (def Definition, err error) {
+	var defJSON definitionJSONv1x10
+	if err := json.Unmarshal(data, &defJSON); err != nil {
+		return Definition{}, errors.Wrap(err, "unmarshal definition v1_10")
+	}
+
+	if len(defJSON.ValidatorAddresses) != defJSON.NumValidators {
+		return Definition{}, errors.New("num_validators not matching validators length")
+	}
+
+	if err := deposit.VerifyDepositAmounts(def.DepositAmounts); err != nil {
+		return Definition{}, errors.Wrap(err, "invalid deposit amounts")
+	}
+
+	return Definition{
+		Name:               defJSON.Name,
+		UUID:               defJSON.UUID,
+		Version:            defJSON.Version,
+		Timestamp:          defJSON.Timestamp,
+		NumValidators:      defJSON.NumValidators,
+		Threshold:          defJSON.Threshold,
+		DKGAlgorithm:       defJSON.DKGAlgorithm,
+		ForkVersion:        defJSON.ForkVersion,
+		ConfigHash:         defJSON.ConfigHash,
+		DefinitionHash:     defJSON.DefinitionHash,
+		Operators:          operatorsFromV1x2orLater(defJSON.Operators),
+		ValidatorAddresses: validatorAddressesFromJSON(defJSON.ValidatorAddresses),
+		Creator: Creator{
+			Address:         defJSON.Creator.Address,
+			ConfigSignature: defJSON.Creator.ConfigSignature,
+		},
+		DepositAmounts:    defJSON.DepositAmounts,
+		ConsensusProtocol: defJSON.ConsensusProtocol,
+		TargetGasLimit:    defJSON.TargetGasLimit,
+	}, nil
+}
+
 // supportEIP712Sigs returns true if the provided definition version supports EIP712 signatures.
 // Note that Definition versions prior to v1.3.0 don't support EIP712 signatures.
 func supportEIP712Sigs(version string) bool {
@@ -858,6 +943,11 @@ func supportPartialDeposits(version string) bool {
 	return !isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7)
 }
 
+// supportTargetGasLimit returns true if the provided definition version supports custom target gas limit.
+func supportTargetGasLimit(version string) bool {
+	return !isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9)
+}
+
 func eip712SigsPresent(operators []Operator) bool {
 	for _, o := range operators {
 		if len(o.ENRSignature) > 0 || len(o.ConfigSignature) > 0 {
@@ -974,6 +1064,26 @@ type definitionJSONv1x9 struct {
 	DefinitionHash     ethHex                    `json:"definition_hash"`
 }
 
+// definitionJSONv1x10 is the json formatter of Definition for versions v1.10 or later.
+type definitionJSONv1x10 struct {
+	Name               string                    `json:"name,omitempty"`
+	Creator            creatorJSON               `json:"creator"`
+	Operators          []operatorJSONv1x2orLater `json:"operators"`
+	UUID               string                    `json:"uuid"`
+	Version            string                    `json:"version"`
+	Timestamp          string                    `json:"timestamp,omitempty"`
+	NumValidators      int                       `json:"num_validators"`
+	Threshold          int                       `json:"threshold"`
+	ValidatorAddresses []validatorAddressesJSON  `json:"validators"`
+	DKGAlgorithm       string                    `json:"dkg_algorithm"`
+	ForkVersion        ethHex                    `json:"fork_version"`
+	DepositAmounts     []eth2p0.Gwei             `json:"deposit_amounts"`
+	ConsensusProtocol  string                    `json:"consensus_protocol"`
+	TargetGasLimit     uint                      `json:"target_gas_limit"`
+	ConfigHash         ethHex                    `json:"config_hash"`
+	DefinitionHash     ethHex                    `json:"definition_hash"`
+}
+
 // Creator identifies the creator of a cluster definition.
 // Note the following struct tag meanings:
 //   - json: json field name. Suffix 0xhex indicates bytes are formatted as 0x prefixed hex strings.
diff --git a/cluster/examples/cluster-definition-006.json b/cluster/examples/cluster-definition-006.json
new file mode 100644
index 00000000..925d683c
--- /dev/null
+++ b/cluster/examples/cluster-definition-006.json
@@ -0,0 +1,55 @@
+{
+  "name": "solo flow",
+  "creator": {
+    "address": "",
+    "config_signature": ""
+  },
+  "operators": [
+    {
+      "address": "",
+      "enr": "enr:-HW4QOOzaUkBDJxca3MoJItjqSv438Ko2ah4oYd6gUczVEReYp9e5Eo6fhwZIG7YYHqzXROm3VVAVX-tJ1W9IQC3XjiAgmlkgnY0iXNlY3AyNTZrMaECOuyMY6-I8YdN_zrY8FrKXdRBAyrGuaxug6eTR_tmQbw",
+      "config_signature": "",
+      "enr_signature": ""
+    },
+    {
+      "address": "",
+      "enr": "enr:-HW4QHjmSl61pUW_gtIoJhqQ-tkB1M1Ovabr0Pp77EyAJD-QXC503L2d2gPgnPtzoxhuhgGjNk8CRSZqtYDNp6uhaaCAgmlkgnY0iXNlY3AyNTZrMaECZBJKObtiUVAbMO0GP09_Kro3AtBhkN30ZgKbNrBZkPo",
+      "config_signature": "",
+      "enr_signature": ""
+    },
+    {
+      "address": "",
+      "enr": "enr:-HW4QHUvGyPKGZ4zDHG69PzFYPgJWKcZiwFV2HrU-41gVYTUCpvA6v-Tdyr4UGgfVHhc9tfMHHhDSlmRUAa-3nlqEnaAgmlkgnY0iXNlY3AyNTZrMaECOmWQK7FDxAtKLuZXWahsxOqIHQbX6WSnTKiJrdOIaZo",
+      "config_signature": "",
+      "enr_signature": ""
+    },
+    {
+      "address": "",
+      "enr": "enr:-HW4QC7kiC4A1x0qVzoQAc_wdXcuTd0UYcOetICL6MJOXskdAjJmfF4pYgFMLx0fCGK3iiv8Cq_mQZ18bt9BvrbeegWAgmlkgnY0iXNlY3AyNTZrMaECXbfZRpz8MygZmrZoobn9dUrLKABO_eojFp1cemlv-18",
+      "config_signature": "",
+      "enr_signature": ""
+    }
+  ],
+  "uuid": "AAA47693-6F13-56CA-D1E1-A70D1E89F3A5",
+  "version": "v1.10.0",
+  "timestamp": "2025-01-09T12:51:06+02:00",
+  "num_validators": 2,
+  "threshold": 3,
+  "validators": [
+    {
+      "fee_recipient_address": "0x0D941218c10b055f0907FE1BbE486ccdAa7e332A",
+      "withdrawal_address": "0x0D941218c10b055f0907FE1BbE486ccdAa7e332A"
+    },
+    {
+      "fee_recipient_address": "0x0D941218c10b055f0907FE1BbE486ccdAa7e332A",
+      "withdrawal_address": "0x0D941218c10b055f0907FE1BbE486ccdAa7e332A"
+    }
+  ],
+  "dkg_algorithm": "default",
+  "fork_version": "0x01017000",
+  "deposit_amounts": null,
+  "consensus_protocol": "",
+  "target_gas_limit": 30000000,
+  "config_hash": "0x10ac111410084511b00cbbbd3fe11c649425a53f2db97322a70520b287089b86",
+  "definition_hash": "0xec542a3aa3dbdce4e57551b491e536eb1bf2abb46dba2c4d238a93075f19318a"
+}
diff --git a/cluster/lock.go b/cluster/lock.go
index b8998440..22d97137 100644
--- a/cluster/lock.go
+++ b/cluster/lock.go
@@ -54,7 +54,7 @@ func (l Lock) MarshalJSON() ([]byte, error) {
 		return marshalLockV1x6(l, lockHash)
 	case isAnyVersion(l.Version, v1_7):
 		return marshalLockV1x7(l, lockHash)
-	case isAnyVersion(l.Version, v1_8, v1_9):
+	case isAnyVersion(l.Version, v1_8, v1_9, v1_10):
 		return marshalLockV1x8OrLater(l, lockHash)
 	default:
 		return nil, errors.New("unsupported version")
@@ -102,7 +102,7 @@ func (l *Lock) UnmarshalJSON(data []byte) error {
 		if err != nil {
 			return err
 		}
-	case isAnyVersion(version.Definition.Version, v1_8, v1_9):
+	case isAnyVersion(version.Definition.Version, v1_8, v1_9, v1_10):
 		lock, err = unmarshalLockV1x8OrLater(data)
 		if err != nil {
 			return err
diff --git a/cluster/manifest/mutationlegacylock.go b/cluster/manifest/mutationlegacylock.go
index 21b25f02..bc023f46 100644
--- a/cluster/manifest/mutationlegacylock.go
+++ b/cluster/manifest/mutationlegacylock.go
@@ -150,6 +150,7 @@ func transformLegacyLock(input *manifestpb.Cluster, signed *manifestpb.SignedMut
 		DkgAlgorithm:      lock.DKGAlgorithm,
 		ForkVersion:       lock.ForkVersion,
 		ConsensusProtocol: lock.ConsensusProtocol,
+		TargetGasLimit:    uint32(lock.TargetGasLimit),
 		Validators:        vals,
 		Operators:         ops,
 	}, nil
diff --git a/cluster/manifestpb/v1/manifest.pb.go b/cluster/manifestpb/v1/manifest.pb.go
index 4437700d..8d166c70 100644
--- a/cluster/manifestpb/v1/manifest.pb.go
+++ b/cluster/manifestpb/v1/manifest.pb.go
@@ -33,6 +33,7 @@ type Cluster struct {
 	Operators           []*Operator            `protobuf:"bytes,7,rep,name=operators,proto3" json:"operators,omitempty"`                                                  // Operators is the list of operators of the cluster.
 	Validators          []*Validator           `protobuf:"bytes,8,rep,name=validators,proto3" json:"validators,omitempty"`                                                // Validators is the list of validators of the cluster.
 	ConsensusProtocol   string                 `protobuf:"bytes,9,opt,name=consensus_protocol,json=consensusProtocol,proto3" json:"consensus_protocol,omitempty"`         // ConsensusProtocol is the consensus protocol name preferred by the cluster, e.g. "abft".
+	TargetGasLimit      uint32                 `protobuf:"varint,10,opt,name=target_gas_limit,json=targetGasLimit,proto3" json:"target_gas_limit,omitempty"`              // TargetGasLimit is the custom target gas limit for transactions.
 	unknownFields       protoimpl.UnknownFields
 	sizeCache           protoimpl.SizeCache
 }
@@ -130,6 +131,13 @@ func (x *Cluster) GetConsensusProtocol() string {
 	return ""
 }
 
+func (x *Cluster) GetTargetGasLimit() uint32 {
+	if x != nil {
+		return x.TargetGasLimit
+	}
+	return 0
+}
+
 // Mutation mutates the cluster manifest.
 type Mutation struct {
 	state         protoimpl.MessageState `protogen:"open.v1"`
@@ -562,7 +570,7 @@ var file_cluster_manifestpb_v1_manifest_proto_rawDesc = []byte{
 	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e,
 	0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x1a, 0x19, 0x67,
 	0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61,
-	0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x99, 0x03, 0x0a, 0x07, 0x43, 0x6c, 0x75,
+	0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x03, 0x0a, 0x07, 0x43, 0x6c, 0x75,
 	0x73, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x15, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f,
 	0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20,
 	0x01, 0x28, 0x0c, 0x52, 0x13, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4d, 0x75, 0x74, 0x61,
@@ -588,57 +596,60 @@ var file_cluster_manifestpb_v1_manifest_proto_rawDesc = []byte{
 	0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73,
 	0x75, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28,
 	0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x50, 0x72, 0x6f, 0x74,
-	0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x60, 0x0a, 0x08, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-	0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
-	0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x04,
-	0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f,
-	0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79,
-	0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x83, 0x01, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x65,
-	0x64, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x75, 0x74,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6c,
-	0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62,
-	0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6d, 0x75,
-	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x1c,
-	0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x59, 0x0a, 0x12,
-	0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69,
-	0x73, 0x74, 0x12, 0x43, 0x0a, 0x09, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
-	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e,
-	0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69,
-	0x67, 0x6e, 0x65, 0x64, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6d, 0x75,
-	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61,
-	0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a,
-	0x03, 0x65, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x22,
-	0xe8, 0x01, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a,
-	0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a,
-	0x70, 0x75, 0x62, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c,
-	0x52, 0x09, 0x70, 0x75, 0x62, 0x53, 0x68, 0x61, 0x72, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x66,
-	0x65, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64,
-	0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x66, 0x65, 0x65, 0x52,
-	0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
-	0x2d, 0x0a, 0x12, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x5f, 0x61, 0x64,
-	0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x69, 0x74,
-	0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3a,
-	0x0a, 0x19, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0c, 0x52, 0x17, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4a, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x0d, 0x56, 0x61,
-	0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x0a, 0x76,
-	0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
-	0x20, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65,
-	0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
-	0x72, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x20, 0x0a,
-	0x0a, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6a,
-	0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22,
-	0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68,
-	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x62, 0x6f, 0x6c, 0x6e, 0x65, 0x74, 0x77, 0x6f,
-	0x72, 0x6b, 0x2f, 0x63, 0x68, 0x61, 0x72, 0x6f, 0x6e, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
-	0x72, 0x2f, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x67,
+	0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e,
+	0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x60,
+	0x0a, 0x08, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61,
+	0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65,
+	0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
+	0x22, 0x83, 0x01, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4d, 0x75, 0x74, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e,
+	0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75,
+	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c,
+	0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e,
+	0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67,
+	0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x59, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64,
+	0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x09,
+	0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x25, 0x2e, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65,
+	0x73, 0x74, 0x70, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4d, 0x75,
+	0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x73, 0x22, 0x36, 0x0a, 0x08, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x0a,
+	0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x72, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x72, 0x22, 0xe8, 0x01, 0x0a, 0x09, 0x56, 0x61,
+	0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69,
+	0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62,
+	0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x5f, 0x73, 0x68,
+	0x61, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x53,
+	0x68, 0x61, 0x72, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x65, 0x63,
+	0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x66, 0x65, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65,
+	0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x77, 0x69, 0x74,
+	0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61,
+	0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x3a, 0x0a, 0x19, 0x62, 0x75, 0x69, 0x6c,
+	0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x4a, 0x73, 0x6f, 0x6e, 0x22, 0x51, 0x0a, 0x0d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
+	0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
+	0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6c, 0x75, 0x73,
+	0x74, 0x65, 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2e, 0x76,
+	0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x0a, 0x76, 0x61, 0x6c,
+	0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x20, 0x0a, 0x0a, 0x4c, 0x65, 0x67, 0x61, 0x63,
+	0x79, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70,
+	0x74, 0x79, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x6f, 0x62, 0x6f, 0x6c, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x63, 0x68, 0x61,
+	0x72, 0x6f, 0x6e, 0x2f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x61, 0x6e, 0x69,
+	0x66, 0x65, 0x73, 0x74, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
 }
 
 var (
diff --git a/cluster/manifestpb/v1/manifest.proto b/cluster/manifestpb/v1/manifest.proto
index 2ccea05f..4959b896 100644
--- a/cluster/manifestpb/v1/manifest.proto
+++ b/cluster/manifestpb/v1/manifest.proto
@@ -17,6 +17,7 @@ message Cluster {
   repeated Operator   operators = 7; // Operators is the list of operators of the cluster.
   repeated Validator validators = 8; // Validators is the list of validators of the cluster.
   string     consensus_protocol = 9; // ConsensusProtocol is the consensus protocol name preferred by the cluster, e.g. "abft".
+  uint32      target_gas_limit = 10; // TargetGasLimit is the custom target gas limit for transactions.
 }
 
 // Mutation mutates the cluster manifest.
diff --git a/cluster/ssz.go b/cluster/ssz.go
index 3d9c1030..715dcc20 100644
--- a/cluster/ssz.go
+++ b/cluster/ssz.go
@@ -29,19 +29,22 @@ const (
 
 // getDefinitionHashFunc returns the function to hash a definition based on the provided version.
 func getDefinitionHashFunc(version string) (func(Definition, ssz.HashWalker, bool) error, error) {
-	if isAnyVersion(version, v1_0, v1_1, v1_2) {
+	switch {
+	case isAnyVersion(version, v1_0, v1_1, v1_2):
 		return hashDefinitionLegacy, nil
-	} else if isAnyVersion(version, v1_3, v1_4) {
+	case isAnyVersion(version, v1_3, v1_4):
 		return hashDefinitionV1x3or4, nil
-	} else if isAnyVersion(version, v1_5, v1_6, v1_7) {
+	case isAnyVersion(version, v1_5, v1_6, v1_7):
 		return hashDefinitionV1x5to7, nil
-	} else if isAnyVersion(version, v1_8) {
+	case isAnyVersion(version, v1_8):
 		return hashDefinitionV1x8, nil
-	} else if isAnyVersion(version, v1_9) {
-		return hashDefinitionV1x9orLater, nil
+	case isAnyVersion(version, v1_9):
+		return hashDefinitionV1x9, nil
+	case isAnyVersion(version, v1_10):
+		return hashDefinitionV1x10, nil
+	default:
+		return nil, errors.New("unknown version", z.Str("version", version))
 	}
-
-	return nil, errors.New("unknown version", z.Str("version", version))
 }
 
 // hashDefinition returns a config or definition hash. The config hash excludes operator ENRs and signatures
@@ -415,8 +418,8 @@ func hashDefinitionV1x5to7(d Definition, hh ssz.HashWalker, configOnly bool) err
 	return hashDefinitionV1x5to9(d, hh, configOnly, nil)
 }
 
-// hashDefinitionV1x8to9 hashes the new definition with extra fields.
-func hashDefinitionV1x8to9(d Definition, hh ssz.HashWalker, configOnly bool, extra []hashExtraFields) error {
+// hashDefinitionV1x8to10 hashes the new definition with extra fields.
+func hashDefinitionV1x8to10(d Definition, hh ssz.HashWalker, configOnly bool, extra []hashExtraFields) error {
 	return hashDefinitionV1x5to9(d, hh, configOnly, []hashExtraFields{
 		func(d Definition, hh ssz.HashWalker) error {
 			// Field (11) 'DepositAmounts' uint64[256]
@@ -443,12 +446,12 @@ func hashDefinitionV1x8to9(d Definition, hh ssz.HashWalker, configOnly bool, ext
 
 // hashDefinitionV1x8 hashes the new definition.
 func hashDefinitionV1x8(d Definition, hh ssz.HashWalker, configOnly bool) error {
-	return hashDefinitionV1x8to9(d, hh, configOnly, nil)
+	return hashDefinitionV1x8to10(d, hh, configOnly, nil)
 }
 
-// hashDefinitionV1x9OrLater hashes the new definition.
-func hashDefinitionV1x9orLater(d Definition, hh ssz.HashWalker, configOnly bool) error {
-	return hashDefinitionV1x8to9(d, hh, configOnly, []hashExtraFields{
+// hashDefinitionV1x9 hashes the new definition.
+func hashDefinitionV1x9(d Definition, hh ssz.HashWalker, configOnly bool) error {
+	return hashDefinitionV1x8to10(d, hh, configOnly, []hashExtraFields{
 		func(d Definition, hh ssz.HashWalker) error {
 			// Field (12) 'ConsensusProtocol' ByteList[256]
 			return putByteList(hh, []byte(d.ConsensusProtocol), sszMaxName, "consensus_protocol")
@@ -456,12 +459,27 @@ func hashDefinitionV1x9orLater(d Definition, hh ssz.HashWalker, configOnly bool)
 	})
 }
 
+// hashDefinitionV1x10 hashes the new definition.
+func hashDefinitionV1x10(d Definition, hh ssz.HashWalker, configOnly bool) error {
+	return hashDefinitionV1x8to10(d, hh, configOnly, []hashExtraFields{
+		func(d Definition, hh ssz.HashWalker) error {
+			// Field (12) 'ConsensusProtocol' ByteList[256]
+			return putByteList(hh, []byte(d.ConsensusProtocol), sszMaxName, "consensus_protocol")
+		},
+		func(d Definition, hh ssz.HashWalker) error {
+			// Field (13) 'TargetGasLimit' uint64
+			hh.PutUint64(uint64(d.TargetGasLimit))
+			return nil
+		},
+	})
+}
+
 // hashLock returns a lock hash.
 func hashLock(l Lock) ([32]byte, error) {
 	var hashFunc func(Lock, ssz.HashWalker) error
 	if isAnyVersion(l.Version, v1_0, v1_1, v1_2) {
 		hashFunc = hashLockLegacy
-	} else if isAnyVersion(l.Version, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9) {
+	} else if isAnyVersion(l.Version, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9, v1_10) {
 		hashFunc = hashLockV1x3orLater
 	} else {
 		return [32]byte{}, errors.New("unknown version")
@@ -524,7 +542,7 @@ func getValidatorHashFunc(version string) (func(DistValidator, ssz.HashWalker, s
 		return hashValidatorV1x3Or4, nil
 	} else if isAnyVersion(version, v1_5, v1_6, v1_7) {
 		return hashValidatorV1x5to7, nil
-	} else if isAnyVersion(version, v1_8, v1_9) {
+	} else if isAnyVersion(version, v1_8, v1_9, v1_10) {
 		return hashValidatorV1x8OrLater, nil
 	}
 
@@ -716,7 +734,7 @@ func getDepositDataHashFunc(version string) (func(DepositData, ssz.HashWalker) e
 		return func(DepositData, ssz.HashWalker) error { return nil }, nil
 	} else if isAnyVersion(version, v1_6) {
 		return hashDepositDataV1x6, nil
-	} else if isAnyVersion(version, v1_7, v1_8, v1_9) {
+	} else if isAnyVersion(version, v1_7, v1_8, v1_9, v1_10) {
 		return hashDepositDataV1x7OrLater, nil
 	}
 
@@ -728,7 +746,7 @@ func getRegistrationHashFunc(version string) (func(BuilderRegistration, ssz.Hash
 	if isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6) {
 		// Noop hash function for v1.0 to v1.6 that do not support builder registration.
 		return func(BuilderRegistration, ssz.HashWalker) error { return nil }, nil
-	} else if isAnyVersion(version, v1_7, v1_8, v1_9) {
+	} else if isAnyVersion(version, v1_7, v1_8, v1_9, v1_10) {
 		return hashBuilderRegistration, nil
 	}
 
diff --git a/cluster/version.go b/cluster/version.go
index cd36cc97..8dcfeda4 100644
--- a/cluster/version.go
+++ b/cluster/version.go
@@ -5,19 +5,20 @@ package cluster
 import "testing"
 
 const (
-	currentVersion = v1_8
+	currentVersion = v1_10
 	dkgAlgo        = "default"
 
-	v1_9 = "v1.9.0"
-	v1_8 = "v1.8.0" // Default
-	v1_7 = "v1.7.0"
-	v1_6 = "v1.6.0"
-	v1_5 = "v1.5.0"
-	v1_4 = "v1.4.0"
-	v1_3 = "v1.3.0"
-	v1_2 = "v1.2.0"
-	v1_1 = "v1.1.0"
-	v1_0 = "v1.0.0"
+	v1_10 = "v1.10.0" // Default
+	v1_9  = "v1.9.0"
+	v1_8  = "v1.8.0"
+	v1_7  = "v1.7.0"
+	v1_6  = "v1.6.0"
+	v1_5  = "v1.5.0"
+	v1_4  = "v1.4.0"
+	v1_3  = "v1.3.0"
+	v1_2  = "v1.2.0"
+	v1_1  = "v1.1.0"
+	v1_0  = "v1.0.0"
 
 	zeroNonce = 0
 
@@ -25,16 +26,17 @@ const (
 )
 
 var supportedVersions = map[string]bool{
-	v1_9: true,
-	v1_8: true,
-	v1_7: true,
-	v1_6: true,
-	v1_5: true,
-	v1_4: true,
-	v1_3: true,
-	v1_2: true,
-	v1_1: true,
-	v1_0: true,
+	v1_10: true,
+	v1_9:  true,
+	v1_8:  true,
+	v1_7:  true,
+	v1_6:  true,
+	v1_5:  true,
+	v1_4:  true,
+	v1_3:  true,
+	v1_2:  true,
+	v1_1:  true,
+	v1_0:  true,
 }
 
 func isAnyVersion(version string, versions ...string) bool {
diff --git a/cmd/addvalidators.go b/cmd/addvalidators.go
index 17edc90c..9fc06de7 100644
--- a/cmd/addvalidators.go
+++ b/cmd/addvalidators.go
@@ -131,7 +131,7 @@ func runAddValidatorsSolo(ctx context.Context, conf addValidatorsConfig) (err er
 		conf.WithdrawalAddrs = repeatAddr(conf.WithdrawalAddrs[0], conf.NumVals)
 	}
 
-	vals, secrets, shareSets, err := genNewVals(len(cluster.GetOperators()), int(cluster.GetThreshold()), cluster.GetForkVersion(), conf)
+	vals, secrets, shareSets, err := genNewVals(ctx, len(cluster.GetOperators()), int(cluster.GetThreshold()), cluster.GetForkVersion(), cluster.GetTargetGasLimit(), conf)
 	if err != nil {
 		return err
 	}
@@ -203,16 +203,21 @@ func runAddValidatorsSolo(ctx context.Context, conf addValidatorsConfig) (err er
 }
 
 // builderRegistration returns a builder registration object using the provided inputs.
-func builderRegistration(secret tbls.PrivateKey, pubkey tbls.PublicKey, feeRecipientAddr string, forkVersion []byte) (*eth2v1.SignedValidatorRegistration, error) {
+func builderRegistration(ctx context.Context, secret tbls.PrivateKey, pubkey tbls.PublicKey, feeRecipientAddr string, forkVersion []byte, targetGasLimit uint32) (*eth2v1.SignedValidatorRegistration, error) {
 	timestamp, err := eth2util.ForkVersionToGenesisTime(forkVersion)
 	if err != nil {
 		return nil, errors.Wrap(err, "invalid fork version")
 	}
 
+	if targetGasLimit == 0 {
+		log.Warn(ctx, "", errors.New("custom target gas limit not supported, setting to default", z.Uint("default_gas_limit", registration.DefaultGasLimit)))
+		targetGasLimit = registration.DefaultGasLimit
+	}
+
 	reg, err := registration.NewMessage(
 		eth2p0.BLSPubKey(pubkey),
 		feeRecipientAddr,
-		registration.DefaultGasLimit,
+		uint64(targetGasLimit),
 		timestamp,
 	)
 	if err != nil {
@@ -384,7 +389,7 @@ func validateConf(conf addValidatorsConfig) error {
 }
 
 // genNewVals returns a list of new validators, their corresponding private keys and threshold keyshares from the provided config.
-func genNewVals(numOps, threshold int, forkVersion []byte, conf addValidatorsConfig) ([]*manifestpb.Validator, []tbls.PrivateKey, [][]tbls.PrivateKey, error) {
+func genNewVals(ctx context.Context, numOps, threshold int, forkVersion []byte, targetGasLimit uint32, conf addValidatorsConfig) ([]*manifestpb.Validator, []tbls.PrivateKey, [][]tbls.PrivateKey, error) {
 	// Generate new validators
 	var (
 		vals      []*manifestpb.Validator
@@ -439,7 +444,7 @@ func genNewVals(numOps, threshold int, forkVersion []byte, conf addValidatorsCon
 		}
 
 		// Generate builder registration
-		builderReg, err := builderRegistration(secret, pubkey, feeRecipientAddr, forkVersion)
+		builderReg, err := builderRegistration(ctx, secret, pubkey, feeRecipientAddr, forkVersion, targetGasLimit)
 		if err != nil {
 			return nil, nil, nil, err
 		}
diff --git a/cmd/createcluster.go b/cmd/createcluster.go
index 14229f20..2be1eec0 100644
--- a/cmd/createcluster.go
+++ b/cmd/createcluster.go
@@ -83,6 +83,8 @@ type clusterConfig struct {
 
 	ConsensusProtocol string
 
+	TargetGasLimit uint
+
 	testnetConfig eth2util.Network
 }
 
@@ -143,6 +145,7 @@ func bindClusterFlags(flags *pflag.FlagSet, config *clusterConfig) {
 	flags.Int64Var(&config.testnetConfig.GenesisTimestamp, "testnet-genesis-timestamp", 0, "Genesis timestamp of the custom test network.")
 	flags.IntSliceVar(&config.DepositAmounts, "deposit-amounts", nil, "List of partial deposit amounts (integers) in ETH. Values must sum up to exactly 32ETH.")
 	flags.StringVar(&config.ConsensusProtocol, "consensus-protocol", "", "Preferred consensus protocol name for the cluster. Selected automatically when not specified.")
+	flags.UintVar(&config.TargetGasLimit, "target-gas-limit", 36000000, "Preferred target gas limit for transactions.")
 }
 
 func bindInsecureFlags(flags *pflag.FlagSet, insecureKeys *bool) {
@@ -276,7 +279,7 @@ func runCreateCluster(ctx context.Context, w io.Writer, conf clusterConfig) erro
 		return err
 	}
 
-	valRegs, err := createValidatorRegistrations(def.FeeRecipientAddresses(), secrets, def.ForkVersion, conf.SplitKeys)
+	valRegs, err := createValidatorRegistrations(ctx, def.FeeRecipientAddresses(), secrets, def.ForkVersion, conf.SplitKeys, conf.TargetGasLimit)
 	if err != nil {
 		return err
 	}
@@ -469,7 +472,7 @@ func signDepositDatas(secrets []tbls.PrivateKey, withdrawalAddresses []string, n
 }
 
 // signValidatorRegistrations returns a slice of validator registrations for each private key in secrets.
-func signValidatorRegistrations(secrets []tbls.PrivateKey, feeAddresses []string, forkVersion []byte, useCurrentTimestamp bool) ([]core.VersionedSignedValidatorRegistration, error) {
+func signValidatorRegistrations(secrets []tbls.PrivateKey, feeAddresses []string, forkVersion []byte, useCurrentTimestamp bool, targetGasLimit uint) ([]core.VersionedSignedValidatorRegistration, error) {
 	if len(secrets) != len(feeAddresses) {
 		return nil, errors.New("insufficient fee addresses")
 	}
@@ -500,7 +503,7 @@ func signValidatorRegistrations(secrets []tbls.PrivateKey, feeAddresses []string
 		unsignedReg, err := registration.NewMessage(
 			eth2p0.BLSPubKey(pk),
 			feeAddress,
-			registration.DefaultGasLimit,
+			uint64(targetGasLimit),
 			timestamp,
 		)
 		if err != nil {
@@ -621,12 +624,17 @@ func createDepositDatas(withdrawalAddresses []string, network string, secrets []
 }
 
 // createValidatorRegistrations creates a slice of builder validator registrations using the provided parameters and returns it.
-func createValidatorRegistrations(feeAddresses []string, secrets []tbls.PrivateKey, forkVersion []byte, useCurrentTimestamp bool) ([]core.VersionedSignedValidatorRegistration, error) {
+func createValidatorRegistrations(ctx context.Context, feeAddresses []string, secrets []tbls.PrivateKey, forkVersion []byte, useCurrentTimestamp bool, targetGasLimit uint) ([]core.VersionedSignedValidatorRegistration, error) {
 	if len(feeAddresses) != len(secrets) {
 		return nil, errors.New("insufficient fee addresses")
 	}
 
-	return signValidatorRegistrations(secrets, feeAddresses, forkVersion, useCurrentTimestamp)
+	if targetGasLimit == 0 {
+		log.Warn(ctx, "", errors.New("custom target gas limit not supported, setting to default", z.Uint("default_gas_limit", registration.DefaultGasLimit)))
+		targetGasLimit = registration.DefaultGasLimit
+	}
+
+	return signValidatorRegistrations(secrets, feeAddresses, forkVersion, useCurrentTimestamp, targetGasLimit)
 }
 
 // writeLock creates a cluster lock and writes it to disk for all peers.
@@ -851,12 +859,9 @@ func newDefFromConfig(ctx context.Context, conf clusterConfig) (cluster.Definiti
 	threshold := safeThreshold(ctx, conf.NumNodes, conf.Threshold)
 
 	var opts []func(*cluster.Definition)
-	if len(conf.DepositAmounts) > 0 {
-		opts = append(opts, cluster.WithVersion(cluster.MinVersionForPartialDeposits))
-	}
 	def, err := cluster.NewDefinition(conf.Name, conf.NumDVs, threshold, feeRecipientAddrs,
 		withdrawalAddrs, forkVersion, cluster.Creator{}, ops, conf.DepositAmounts,
-		conf.ConsensusProtocol, rand.Reader, opts...)
+		conf.ConsensusProtocol, conf.TargetGasLimit, rand.Reader, opts...)
 	if err != nil {
 		return cluster.Definition{}, err
 	}
diff --git a/cmd/createdkg.go b/cmd/createdkg.go
index 41923d59..8b66c06e 100644
--- a/cmd/createdkg.go
+++ b/cmd/createdkg.go
@@ -34,6 +34,7 @@ type createDKGConfig struct {
 	DepositAmounts    []int // Amounts specified in ETH (integers).
 	OperatorENRs      []string
 	ConsensusProtocol string
+	TargetGasLimit    uint
 }
 
 func newCreateDKGCmd(runFunc func(context.Context, createDKGConfig) error) *cobra.Command {
@@ -84,6 +85,7 @@ func bindCreateDKGFlags(cmd *cobra.Command, config *createDKGConfig) {
 	cmd.Flags().IntSliceVar(&config.DepositAmounts, "deposit-amounts", nil, "List of partial deposit amounts (integers) in ETH. Values must sum up to exactly 32ETH.")
 	cmd.Flags().StringSliceVar(&config.OperatorENRs, operatorENRs, nil, "[REQUIRED] Comma-separated list of each operator's Charon ENR address.")
 	cmd.Flags().StringVar(&config.ConsensusProtocol, "consensus-protocol", "", "Preferred consensus protocol name for the cluster. Selected automatically when not specified.")
+	cmd.Flags().UintVar(&config.TargetGasLimit, "target-gas-limit", 36000000, "Preferred target gas limit for transactions.")
 
 	mustMarkFlagRequired(cmd, operatorENRs)
 }
@@ -144,14 +146,11 @@ func runCreateDKG(ctx context.Context, conf createDKGConfig) (err error) {
 
 	var opts []func(*cluster.Definition)
 	opts = append(opts, cluster.WithDKGAlgorithm(conf.DKGAlgo))
-	if len(conf.DepositAmounts) > 0 {
-		opts = append(opts, cluster.WithVersion(cluster.MinVersionForPartialDeposits))
-	}
 	def, err := cluster.NewDefinition(
 		conf.Name, conf.NumValidators, conf.Threshold,
 		conf.FeeRecipientAddrs, conf.WithdrawalAddrs,
 		forkVersion, cluster.Creator{}, operators, conf.DepositAmounts,
-		conf.ConsensusProtocol, crand.Reader, opts...)
+		conf.ConsensusProtocol, conf.TargetGasLimit, crand.Reader, opts...)
 	if err != nil {
 		return err
 	}
diff --git a/core/validatorapi/validatorapi.go b/core/validatorapi/validatorapi.go
index 49a86eb5..86312771 100644
--- a/core/validatorapi/validatorapi.go
+++ b/core/validatorapi/validatorapi.go
@@ -33,8 +33,8 @@ import (
 )
 
 const (
-	gasLimit    = 30000000
-	zeroAddress = "0x0000000000000000000000000000000000000000"
+	defaultGasLimit = 30000000
+	zeroAddress     = "0x0000000000000000000000000000000000000000"
 )
 
 // SlotFromTimestamp returns the Ethereum slot associated to a timestamp, given the genesis configuration fetched
@@ -86,7 +86,7 @@ func NewComponentInsecure(_ *testing.T, eth2Cl eth2wrap.Client, shareIdx int) (*
 
 // NewComponent returns a new instance of the validator API core workflow component.
 func NewComponent(eth2Cl eth2wrap.Client, allPubSharesByKey map[core.PubKey]map[int]tbls.PublicKey,
-	shareIdx int, feeRecipientFunc func(core.PubKey) string, builderEnabled bool, seenPubkeys func(core.PubKey),
+	shareIdx int, feeRecipientFunc func(core.PubKey) string, builderEnabled bool, targetGasLimit uint, seenPubkeys func(core.PubKey),
 ) (*Component, error) {
 	var (
 		sharesByKey     = make(map[eth2p0.BLSPubKey]eth2p0.BLSPubKey)
@@ -168,6 +168,7 @@ func NewComponent(eth2Cl eth2wrap.Client, allPubSharesByKey map[core.PubKey]map[
 		shareIdx:           shareIdx,
 		feeRecipientFunc:   feeRecipientFunc,
 		builderEnabled:     builderEnabled,
+		targetGasLimit:     targetGasLimit,
 		swallowRegFilter:   log.Filter(),
 	}, nil
 }
@@ -178,6 +179,7 @@ type Component struct {
 	insecureTest     bool
 	feeRecipientFunc func(core.PubKey) string
 	builderEnabled   bool
+	targetGasLimit   uint
 	swallowRegFilter z.Field
 
 	// getVerifyShareFunc maps public shares (what the VC thinks as its public key)
@@ -1276,13 +1278,20 @@ func (c Component) getAggregateSyncCommSelection(ctx context.Context, psigsBySlo
 
 // ProposerConfig returns the proposer configuration for all validators.
 func (c Component) ProposerConfig(ctx context.Context) (*eth2exp.ProposerConfigResponse, error) {
+	var targetGasLimit uint
+	if c.targetGasLimit == 0 {
+		log.Warn(ctx, "", errors.New("custom target gas limit not supported, setting to default", z.Uint("default_gas_limit", defaultGasLimit)))
+		targetGasLimit = defaultGasLimit
+	} else {
+		targetGasLimit = c.targetGasLimit
+	}
 	resp := eth2exp.ProposerConfigResponse{
 		Proposers: make(map[eth2p0.BLSPubKey]eth2exp.ProposerConfig),
 		Default: eth2exp.ProposerConfig{ // Default doesn't make sense, disable for now.
 			FeeRecipient: zeroAddress,
 			Builder: eth2exp.Builder{
 				Enabled:  false,
-				GasLimit: gasLimit,
+				GasLimit: targetGasLimit,
 			},
 		},
 	}
@@ -1313,7 +1322,7 @@ func (c Component) ProposerConfig(ctx context.Context) (*eth2exp.ProposerConfigR
 			FeeRecipient: c.feeRecipientFunc(pubkey),
 			Builder: eth2exp.Builder{
 				Enabled:  c.builderEnabled,
-				GasLimit: gasLimit,
+				GasLimit: targetGasLimit,
 				Overrides: map[string]string{
 					"timestamp":  strconv.FormatInt(timestamp.Unix(), 10),
 					"public_key": string(pubkey),
diff --git a/dkg/dkg.go b/dkg/dkg.go
index ee890dde..23dd9752 100644
--- a/dkg/dkg.go
+++ b/dkg/dkg.go
@@ -111,7 +111,7 @@ func Run(ctx context.Context, conf Config) (err error) {
 	}
 
 	// This DKG only supports a few specific config versions.
-	if def.Version != "v1.6.0" && def.Version != "v1.7.0" && def.Version != "v1.8.0" {
+	if def.Version != "v1.6.0" && def.Version != "v1.7.0" && def.Version != "v1.8.0" && def.Version != "v1.9.0" && def.Version != "v1.10.0" {
 		return errors.New("only v1.6.0, v1.7.0 and v1.8.0 cluster definition versions supported")
 	}
 
@@ -267,7 +267,7 @@ func Run(ctx context.Context, conf Config) (err error) {
 		ex,
 		shares,
 		def.FeeRecipientAddresses(),
-		registration.DefaultGasLimit,
+		uint64(def.TargetGasLimit),
 		nodeIdx,
 		def.ForkVersion,
 	)
@@ -638,11 +638,16 @@ func signAndAggValidatorRegistrations(
 	ex *exchanger,
 	shares []share,
 	feeRecipients []string,
-	gasLimit uint64,
+	targetGasLimit uint64,
 	nodeIdx cluster.NodeIdx,
 	forkVersion []byte,
 ) ([]core.VersionedSignedValidatorRegistration, error) {
-	parSig, valRegs, err := signValidatorRegistrations(shares, nodeIdx.ShareIdx, feeRecipients, gasLimit, forkVersion)
+	if targetGasLimit == 0 {
+		log.Warn(ctx, "", errors.New("custom target gas limit not supported, setting to default", z.Uint("default_gas_limit", registration.DefaultGasLimit)))
+		targetGasLimit = registration.DefaultGasLimit
+	}
+
+	parSig, valRegs, err := signValidatorRegistrations(shares, nodeIdx.ShareIdx, feeRecipients, targetGasLimit, forkVersion)
 	if err != nil {
 		return nil, err
 	}
diff --git a/docs/configuration.md b/docs/configuration.md
index 1186f5d5..acabe9a1 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -87,7 +87,13 @@ on how an individual `distributed_validator` looks like.
 ### Cluster Config Change Log
 
 The following is the historical change log of the cluster config:
-- `v1.8.0` **default**:
+- `v1.10.0` **default**:
+  - Added the `target_gas_limit` field to cluster lock which contains the prefered target gas limit for transactions.
+  - When not specified, the default value of `36000000` will be used.
+- `v1.9.0`:
+  - Added the `consensus_protocol` field to cluster lock which contains the prefered consensus protocol for the cluster.
+  - When not specified, the default value of `qbft` will be used.
+- `v1.8.0`:
   - Added the `deposit_amounts` list to cluster lock which contains partial deposit amounts in gwei.
   - When not specified, the single value of 32ETH will be used. All partial amounts must sum up to 32ETH.
   - `distributed_validator` structure replaced `deposit_data` with `partial_deposit_data` respectively.



Test patch:
diff --git a/app/obolapi/api_test.go b/app/obolapi/api_test.go
index bb6f0de1..bda4d122 100644
--- a/app/obolapi/api_test.go
+++ b/app/obolapi/api_test.go
@@ -43,6 +43,7 @@ func TestLockPublish(t *testing.T) {
 		opts := []func(d *cluster.Definition){
 			func(d *cluster.Definition) {
 				d.Version = "v1.5.0"
+				d.TargetGasLimit = 0
 			},
 		}
 
diff --git a/cluster/cluster_internal_test.go b/cluster/cluster_internal_test.go
index d09fc89d..7724e787 100644
--- a/cluster/cluster_internal_test.go
+++ b/cluster/cluster_internal_test.go
@@ -22,8 +22,9 @@ func TestDefinitionVerify(t *testing.T) {
 	secret3, creator := randomCreator(t)
 
 	t.Run("verify definition v1.5 solo", func(t *testing.T) {
-		definition := randomDefinition(t, creator, Operator{}, Operator{},
+		definition := randomDefinition(t, creator, Operator{}, Operator{}, 0,
 			WithVersion(v1_5),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 
 		definition, err = signCreator(secret3, definition)
@@ -34,8 +35,9 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("verify definition v1.5", func(t *testing.T) {
-		definition := randomDefinition(t, creator, op0, op1,
+		definition := randomDefinition(t, creator, op0, op1, 0,
 			WithVersion(v1_5),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 
 		definition, err = signCreator(secret3, definition)
@@ -52,9 +54,10 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("verify definition v1.4", func(t *testing.T) {
-		definition := randomDefinition(t, creator, op0, op1,
+		definition := randomDefinition(t, creator, op0, op1, 0,
 			WithVersion(v1_4),
 			WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 
 		definition, err = signCreator(secret3, definition)
@@ -71,9 +74,10 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("verify definition v1.3", func(t *testing.T) {
-		definition := randomDefinition(t, Creator{}, op0, op1,
+		definition := randomDefinition(t, Creator{}, op0, op1, 0,
 			WithVersion(v1_3),
 			WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 
 		definition.Operators[0], err = signOperator(secret0, definition, op0)
@@ -87,21 +91,23 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("verify definition v1.2 or lower", func(t *testing.T) {
-		def := randomDefinition(t, Creator{}, op0, op1,
+		def := randomDefinition(t, Creator{}, op0, op1, 0,
 			WithVersion(v1_2),
 			WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 		require.NoError(t, def.VerifySignatures())
 
-		def = randomDefinition(t, Creator{}, op0, op1,
+		def = randomDefinition(t, Creator{}, op0, op1, 0,
 			WithVersion(v1_0),
 			WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 		require.NoError(t, def.VerifySignatures())
 	})
 
 	t.Run("unsigned creator and operators", func(t *testing.T) {
-		def := randomDefinition(t, creator, op0, op1)
+		def := randomDefinition(t, creator, op0, op1, 30000000)
 		def.Creator = Creator{}
 		def.Operators = []Operator{{}, {}}
 
@@ -109,9 +115,10 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("unsigned operators v1.3", func(t *testing.T) {
-		def := randomDefinition(t, creator, op0, op1,
+		def := randomDefinition(t, creator, op0, op1, 0,
 			WithVersion(v1_3),
 			WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()),
+			func(d *Definition) { d.TargetGasLimit = 0 },
 		)
 
 		def.Operators = []Operator{{}, {}}
@@ -120,7 +127,7 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("empty operator signatures", func(t *testing.T) {
-		def := randomDefinition(t, creator, op0, op1)
+		def := randomDefinition(t, creator, op0, op1, 30000000)
 
 		// Empty ENR sig
 		err := def.VerifySignatures()
@@ -135,7 +142,7 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("some operators didn't sign", func(t *testing.T) {
-		definition := randomDefinition(t, creator, op0, op1)
+		definition := randomDefinition(t, creator, op0, op1, 30000000)
 		definition.Operators[0] = Operator{} // Operator with no address, enr sig or config sig
 
 		// Only operator 1 signed.
@@ -148,14 +155,14 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("no operators no creator", func(t *testing.T) {
-		definition := randomDefinition(t, Creator{}, Operator{}, Operator{})
+		definition := randomDefinition(t, Creator{}, Operator{}, Operator{}, 30000000)
 
 		err = definition.VerifySignatures()
 		require.NoError(t, err)
 	})
 
 	t.Run("creator didn't sign", func(t *testing.T) {
-		definition := randomDefinition(t, creator, op0, op1)
+		definition := randomDefinition(t, creator, op0, op1, 30000000)
 		definition.Operators[0], err = signOperator(secret0, definition, op0)
 		require.NoError(t, err)
 
@@ -168,7 +175,7 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("solo flow definition empty operators slice", func(t *testing.T) {
-		definition := randomDefinition(t, creator, Operator{}, Operator{}, func(def *Definition) {
+		definition := randomDefinition(t, creator, Operator{}, Operator{}, 30000000, func(def *Definition) {
 			def.Operators = []Operator{}
 		})
 
@@ -186,7 +193,7 @@ func TestDefinitionVerify(t *testing.T) {
 	})
 
 	t.Run("solo flow definition empty operator structs", func(t *testing.T) {
-		definition := randomDefinition(t, creator, Operator{}, Operator{}, func(definition *Definition) {
+		definition := randomDefinition(t, creator, Operator{}, Operator{}, 30000000, func(definition *Definition) {
 			definition.Name = "solo flow"
 		})
 
@@ -233,8 +240,8 @@ func randomOperator(t *testing.T) (*k1.PrivateKey, Operator) {
 	}
 }
 
-// randomDefinition returns a test cluster definition with version set to v1.4.0.
-func randomDefinition(t *testing.T, cr Creator, op0, op1 Operator, opts ...func(*Definition)) Definition {
+// randomDefinition returns a test cluster definition with version set to default.
+func randomDefinition(t *testing.T, cr Creator, op0, op1 Operator, targetGasLimit uint, opts ...func(*Definition)) Definition {
 	t.Helper()
 
 	const (
@@ -250,7 +257,7 @@ func randomDefinition(t *testing.T, cr Creator, op0, op1 Operator, opts ...func(
 
 	definition, err := NewDefinition("test definition", numVals, threshold,
 		feeRecipientAddrs, withdrawalAddrs, eth2util.Sepolia.GenesisForkVersionHex, cr, []Operator{op0, op1}, nil,
-		"qbft", rand.New(rand.NewSource(1)), opts...)
+		"qbft", targetGasLimit, rand.New(rand.NewSource(1)), opts...)
 	require.NoError(t, err)
 
 	return definition
diff --git a/cluster/cluster_test.go b/cluster/cluster_test.go
index e52a9b54..cc832b25 100644
--- a/cluster/cluster_test.go
+++ b/cluster/cluster_test.go
@@ -21,16 +21,17 @@ import (
 //go:generate go test . -v -update -clean
 
 const (
-	v1_9 = "v1.9.0"
-	v1_8 = "v1.8.0"
-	v1_7 = "v1.7.0"
-	v1_6 = "v1.6.0"
-	v1_5 = "v1.5.0"
-	v1_4 = "v1.4.0"
-	v1_3 = "v1.3.0"
-	v1_2 = "v1.2.0"
-	v1_1 = "v1.1.0"
-	v1_0 = "v1.0.0"
+	v1_10 = "v1.10.0"
+	v1_9  = "v1.9.0"
+	v1_8  = "v1.8.0"
+	v1_7  = "v1.7.0"
+	v1_6  = "v1.6.0"
+	v1_5  = "v1.5.0"
+	v1_4  = "v1.4.0"
+	v1_3  = "v1.3.0"
+	v1_2  = "v1.2.0"
+	v1_1  = "v1.1.0"
+	v1_0  = "v1.0.0"
 )
 
 // TestEncode tests whether charon can correctly encode lock and definition files.
@@ -63,10 +64,15 @@ func TestEncode(t *testing.T) {
 			}
 
 			var partialAmounts []int
-			if isAnyVersion(version, v1_8, v1_9) {
+			if isAnyVersion(version, v1_8, v1_9, v1_10) {
 				partialAmounts = []int{16, 16}
 			}
 
+			targetGasLimit := uint(0)
+			if isAnyVersion(version, v1_10) {
+				targetGasLimit = 30000000
+			}
+
 			definition, err := cluster.NewDefinition(
 				"test definition",
 				numVals,
@@ -94,6 +100,7 @@ func TestEncode(t *testing.T) {
 				},
 				partialAmounts,
 				"abft",
+				targetGasLimit,
 				rand.New(rand.NewSource(0)),
 				opts...,
 			)
@@ -123,6 +130,11 @@ func TestEncode(t *testing.T) {
 				definition.ConsensusProtocol = ""
 			}
 
+			// Definition version prior to v1.10.0 don't support TargetGasLimit.
+			if isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9) {
+				definition.TargetGasLimit = 0
+			}
+
 			t.Run("definition_json_"+vStr, func(t *testing.T) {
 				testutil.RequireGoldenJSON(t, definition,
 					testutil.WithFilename("cluster_definition_"+vStr+".json"))
@@ -197,7 +209,7 @@ func TestEncode(t *testing.T) {
 			}
 
 			// Lock versions v1.8.0 and later support multiple PartialDepositData.
-			if isAnyVersion(version, v1_8, v1_9) {
+			if !isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7) {
 				for i := range lock.Validators {
 					dd := cluster.RandomDepositDataSeed(r)
 					dd.PubKey = lock.Validators[i].PubKey
diff --git a/cluster/manifest/cluster_test.go b/cluster/manifest/cluster_test.go
index e6a77168..80e06da4 100644
--- a/cluster/manifest/cluster_test.go
+++ b/cluster/manifest/cluster_test.go
@@ -13,6 +13,30 @@ import (
 	manifestpb "github.com/obolnetwork/charon/cluster/manifestpb/v1"
 )
 
+const (
+	v1_10 = "v1.10.0"
+	v1_9  = "v1.9.0"
+	v1_8  = "v1.8.0"
+	v1_7  = "v1.7.0"
+	v1_6  = "v1.6.0"
+	v1_5  = "v1.5.0"
+	v1_4  = "v1.4.0"
+	v1_3  = "v1.3.0"
+	v1_2  = "v1.2.0"
+	v1_1  = "v1.1.0"
+	v1_0  = "v1.0.0"
+)
+
+func isAnyVersion(version string, list ...string) bool {
+	for _, v := range list {
+		if version == v {
+			return true
+		}
+	}
+
+	return false
+}
+
 func TestDuplicateENRs(t *testing.T) {
 	seed := 0
 	random := rand.New(rand.NewSource(int64(seed)))
diff --git a/cluster/manifest/load_test.go b/cluster/manifest/load_test.go
index c6524b7a..4cb3f490 100644
--- a/cluster/manifest/load_test.go
+++ b/cluster/manifest/load_test.go
@@ -111,10 +111,16 @@ func testLoadLegacy(t *testing.T, version string) {
 
 	var opts []func(*cluster.Definition)
 	opts = append(opts, cluster.WithVersion(version))
-	if version < "v1.5.0" {
+	if isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4) {
 		opts = append(opts, cluster.WithLegacyVAddrs(testutil.RandomETHAddress(), testutil.RandomETHAddress()))
 	}
 
+	if isAnyVersion(version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9) {
+		opts = append(opts, func(d *cluster.Definition) { d.TargetGasLimit = 0 })
+	} else {
+		opts = append(opts, func(d *cluster.Definition) { d.TargetGasLimit = 36000000 })
+	}
+
 	seed := 0
 	random := rand.New(rand.NewSource(int64(seed)))
 	lock, _, _ := cluster.NewForT(t, rand.Intn(10), k, n, seed, random, opts...)
diff --git a/cluster/test_cluster.go b/cluster/test_cluster.go
index b31714f8..b16c57ab 100644
--- a/cluster/test_cluster.go
+++ b/cluster/test_cluster.go
@@ -117,7 +117,7 @@ func NewForT(t *testing.T, dv, k, n, seed int, random *rand.Rand, opts ...func(*
 	def, err := NewDefinition("test cluster", dv, k,
 		feeRecipientAddrs, withdrawalAddrs,
 		eth2util.Goerli.GenesisForkVersionHex, creator, ops, nil,
-		"", randomReader, opts...)
+		"", 30000000, randomReader, opts...)
 	require.NoError(t, err)
 
 	// Definition version prior to v1.3.0 don't support EIP712 signatures.
diff --git a/cluster/testdata/cluster_definition_v1_10_0.json b/cluster/testdata/cluster_definition_v1_10_0.json
new file mode 100644
index 00000000..8b557964
--- /dev/null
+++ b/cluster/testdata/cluster_definition_v1_10_0.json
@@ -0,0 +1,46 @@
+{
+ "name": "test definition",
+ "creator": {
+  "address": "0x6325253fec738dd7a9e28bf921119c160f070244",
+  "config_signature": "0x0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d0836bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f1c"
+ },
+ "operators": [
+  {
+   "address": "0x094279db1944ebd7a19d0f7bbacbe0255aa5b7d4",
+   "enr": "enr://b0223beea5f4f74391f445d15afd4294040374f6924b98cbf8713f8d962d7c8d",
+   "config_signature": "0x019192c24224e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6de0374366c4719e43a1b067d89bc7f01f1f573981659a44ff17a4c1c",
+   "enr_signature": "0x15a3b539eb1e5849c6077dbb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f4125c8fa7311e4d7defa922daae7786667f7e936cd4f24ab1c"
+  },
+  {
+   "address": "0xdf866baa56038367ad6145de1ee8f4a8b0993ebd",
+   "enr": "enr://e56a156a8de563afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e4d",
+   "config_signature": "0xa6430105220d0b29688b734b8ea0f3ca9936e8461f10d77c96ea80a7a665f606f6a63b7f3dfd2567c18979e4d60f26686d9bf2fb26c901ff354cde1607ee294b1b",
+   "enr_signature": "0xf32b7c7822ba64f84ab43ca0c6e6b91c1fd3be8990434179d3af4491a369012db92d184fc39d1734ff5716428953bb6865fcf92b0c3a17c9028be9914eb7649c1c"
+  }
+ ],
+ "uuid": "0194FDC2-FA2F-FCC0-41D3-FF12045B73C8",
+ "version": "v1.10.0",
+ "timestamp": "2022-07-19T18:19:58+02:00",
+ "num_validators": 2,
+ "threshold": 3,
+ "validators": [
+  {
+   "fee_recipient_address": "0x52fdfc072182654f163f5f0f9a621d729566c74d",
+   "withdrawal_address": "0x81855ad8681d0d86d1e91e00167939cb6694d2c4"
+  },
+  {
+   "fee_recipient_address": "0xeb9d18a44784045d87f3c67cf22746e995af5a25",
+   "withdrawal_address": "0x5fb90badb37c5821b6d95526a41a9504680b4e7c"
+  }
+ ],
+ "dkg_algorithm": "default",
+ "fork_version": "0x90000069",
+ "deposit_amounts": [
+  "16000000000",
+  "16000000000"
+ ],
+ "consensus_protocol": "abft",
+ "target_gas_limit": 30000000,
+ "config_hash": "0xafad2b3c34a7579fdd38c7a8d2b9f1ea5c7d0f940d2fbbcd2a383258ce8d76a2",
+ "definition_hash": "0x174b33b12bcb1ed2313c3a7b1c11dd348ccf21db13d987b0c9722df44bd62da0"
+}
\ No newline at end of file
diff --git a/cluster/testdata/cluster_lock_v1_10_0.json b/cluster/testdata/cluster_lock_v1_10_0.json
new file mode 100644
index 00000000..d500947c
--- /dev/null
+++ b/cluster/testdata/cluster_lock_v1_10_0.json
@@ -0,0 +1,116 @@
+{
+ "cluster_definition": {
+  "name": "test definition",
+  "creator": {
+   "address": "0x6325253fec738dd7a9e28bf921119c160f070244",
+   "config_signature": "0x0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d0836bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f1c"
+  },
+  "operators": [
+   {
+    "address": "0x094279db1944ebd7a19d0f7bbacbe0255aa5b7d4",
+    "enr": "enr://b0223beea5f4f74391f445d15afd4294040374f6924b98cbf8713f8d962d7c8d",
+    "config_signature": "0x019192c24224e2cafccae3a61fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6de0374366c4719e43a1b067d89bc7f01f1f573981659a44ff17a4c1c",
+    "enr_signature": "0x15a3b539eb1e5849c6077dbb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f4125c8fa7311e4d7defa922daae7786667f7e936cd4f24ab1c"
+   },
+   {
+    "address": "0xdf866baa56038367ad6145de1ee8f4a8b0993ebd",
+    "enr": "enr://e56a156a8de563afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e4d",
+    "config_signature": "0xa6430105220d0b29688b734b8ea0f3ca9936e8461f10d77c96ea80a7a665f606f6a63b7f3dfd2567c18979e4d60f26686d9bf2fb26c901ff354cde1607ee294b1b",
+    "enr_signature": "0xf32b7c7822ba64f84ab43ca0c6e6b91c1fd3be8990434179d3af4491a369012db92d184fc39d1734ff5716428953bb6865fcf92b0c3a17c9028be9914eb7649c1c"
+   }
+  ],
+  "uuid": "0194FDC2-FA2F-FCC0-41D3-FF12045B73C8",
+  "version": "v1.10.0",
+  "timestamp": "2022-07-19T18:19:58+02:00",
+  "num_validators": 2,
+  "threshold": 3,
+  "validators": [
+   {
+    "fee_recipient_address": "0x52fdfc072182654f163f5f0f9a621d729566c74d",
+    "withdrawal_address": "0x81855ad8681d0d86d1e91e00167939cb6694d2c4"
+   },
+   {
+    "fee_recipient_address": "0xeb9d18a44784045d87f3c67cf22746e995af5a25",
+    "withdrawal_address": "0x5fb90badb37c5821b6d95526a41a9504680b4e7c"
+   }
+  ],
+  "dkg_algorithm": "default",
+  "fork_version": "0x90000069",
+  "deposit_amounts": [
+   "16000000000",
+   "16000000000"
+  ],
+  "consensus_protocol": "abft",
+  "target_gas_limit": 30000000,
+  "config_hash": "0xafad2b3c34a7579fdd38c7a8d2b9f1ea5c7d0f940d2fbbcd2a383258ce8d76a2",
+  "definition_hash": "0x174b33b12bcb1ed2313c3a7b1c11dd348ccf21db13d987b0c9722df44bd62da0"
+ },
+ "distributed_validators": [
+  {
+   "distributed_public_key": "0x1814be823350eab13935f31d84484517e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da102",
+   "public_shares": [
+    "0x975deda77e758579ea3dfe4136abf752b3b8271d03e944b3c9db366b75045f8efd69d22ae5411947cb553d7694267aef",
+    "0x4ebcea406b32d6108bd68584f57e37caac6e33feaa3263a399437024ba9c9b14678a274f01a910ae295f6efbfe5f5abf"
+   ],
+   "builder_registration": {
+    "message": {
+     "fee_recipient": "0x89b79bf504cfb57c7601232d589baccea9d6e263",
+     "gas_limit": 30000000,
+     "timestamp": 1655733600,
+     "pubkey": "0x1814be823350eab13935f31d84484517e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da102"
+    },
+    "signature": "0xd313c8a3b4c1c0e05447f4ba370eb36dbcfdec90b302dcdc3b9ef522e2a6f1ed0afec1f8e20faabedf6b162e717d3a748a58677a0c56348f8921a266b11d0f334c62fe52ba53af19779cb2948b6570ffa0b773963c130ad797ddeafe4e3ad29b"
+   },
+   "partial_deposit_data": [
+    {
+     "pubkey": "0x1814be823350eab13935f31d84484517e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da102",
+     "withdrawal_credentials": "0x76b0620556304a3e3eae14c28d0cea39d2901a52720da85ca1e4b38eaf3f44c6",
+     "amount": "5919415281453547599",
+     "signature": "0xc6ef8362f2f5640854c15dfcacaa8a2cecce5a3aba53ab705b18db94b4d338a5143e63408d8724b0cf3fae17a3f79be1072fb63c35d6042c4160f38ee9e2a9f3fb4ffb0019b454d522b5ffa17604193fb8966710a7960732ca52cf53c3f520c8"
+    },
+    {
+     "pubkey": "0x1814be823350eab13935f31d84484517e924aef78ae151c00755925836b7075885650c30ec29a3703934bf50a28da102",
+     "withdrawal_credentials": "0xc7ae77ba1d259b188a4b21c86fbc23d728b45347eada650af24c56d0800a8691",
+     "amount": "8817733914007551237",
+     "signature": "0x332088a8b07590bafcccbec6177536401d9a2b7f512b54bfc9d00532adf5aaa7c3a96bc59b489f77d9042c5bce26b163defde5ee6a0fbb3e9346cef81f0ae9515ef30fa47a364e75aea9e111d596e685a591121966e031650d510354aa845580"
+    }
+   ]
+  },
+  {
+   "distributed_public_key": "0x5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00ce73bff706f7ff4b6f44090a32711f3208e4e",
+   "public_shares": [
+    "0x4b89cb5165ce64002cbd9c2887aa113df2468928d5a23b9ca740f80c9382d9c6034ad2960c796503e1ce221725f50caf",
+    "0x1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964ed47f74aa594468ced323cb76f0d3fac476c9f"
+   ],
+   "builder_registration": {
+    "message": {
+     "fee_recipient": "0x72e6415a761f03abaa40abc9448fddeb2191d945",
+     "gas_limit": 30000000,
+     "timestamp": 1655733600,
+     "pubkey": "0x5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00ce73bff706f7ff4b6f44090a32711f3208e4e"
+    },
+    "signature": "0xe65a31bd5d41e2d2ce9c2b17892f0fea1931a290220777a93143dfdcbfa68406e877073ff08834e197a4034aa48afa3f85b8a62708caebbac880b5b89b93da53810164402104e648b6226a1b78021851f5d9ac0f313a89ddfc454c5f8f72ac89"
+   },
+   "partial_deposit_data": [
+    {
+     "pubkey": "0x5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00ce73bff706f7ff4b6f44090a32711f3208e4e",
+     "withdrawal_credentials": "0x0152e5d49435807f9d4b97be6fb77970466a5626fe33408cf9e88e2c797408a3",
+     "amount": "534275443587623213",
+     "signature": "0x329cfffd4a75e498320982c85aad70384859c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92cef9046efa18500944cbe800a0b1527ea64729a861d2f6497a3235c37f4192779ec1d96b3b1c5424fce0b727b030"
+    },
+    {
+     "pubkey": "0x5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd58b00ce73bff706f7ff4b6f44090a32711f3208e4e",
+     "withdrawal_credentials": "0x078143ee26a586ad23139d5041723470bf24a865837c9123461c41f5ff99aa99",
+     "amount": "2408919902728845389",
+     "signature": "0xce24eb65491622558fdf297b9fa007864bafd7cd4ca1b2fb5766ab431a032b72b9a7e937ed648d0801f29055d3090d2463718254f9442483c7b98b938045da519843854b0ed3f7ba951a493f321f0966603022c1dfc579b99ed9d20d573ad531"
+    }
+   ]
+  }
+ ],
+ "signature_aggregate": "0x9347800979d1830356f2a54c3deab2a4b4475d63afbe8fb56987c77f5818526f",
+ "lock_hash": "0x3511c8de562186b1a95cb4fd73a30a26707cd05003e4050134254cb30f7e456e",
+ "node_signatures": [
+  "0xb38b19f53784c19e9beac03c875a27db029de37ae37a42318813487685929359",
+  "0xca8c5eb94e152dc1af42ea3d1676c1bdd19ab8e2925c6daee4de5ef9f9dcf08d"
+ ]
+}
\ No newline at end of file
diff --git a/cmd/createcluster_internal_test.go b/cmd/createcluster_internal_test.go
index 46a09fc8..ccc0dabd 100644
--- a/cmd/createcluster_internal_test.go
+++ b/cmd/createcluster_internal_test.go
@@ -35,7 +35,7 @@ import (
 //go:generate go test . -run=TestCreateCluster -update
 
 func TestCreateCluster(t *testing.T) {
-	defPath := "../cluster/examples/cluster-definition-005.json"
+	defPath := "../cluster/examples/cluster-definition-006.json"
 	def, err := loadDefinition(context.Background(), defPath)
 	require.NoError(t, err)
 
@@ -224,7 +224,7 @@ func TestCreateCluster(t *testing.T) {
 				NumNodes:  3,
 				Threshold: 3,
 				NumDVs:    5,
-				Network:   "goerli",
+				Network:   eth2util.Goerli.Name,
 			},
 			Prep: func(t *testing.T, config clusterConfig) clusterConfig {
 				t.Helper()
@@ -269,7 +269,7 @@ func TestCreateCluster(t *testing.T) {
 				NumNodes:  2,
 				Threshold: 2,
 				NumDVs:    1,
-				Network:   "goerli",
+				Network:   eth2util.Goerli.Name,
 			},
 			defFileProvider: func() []byte {
 				data, err := json.Marshal(defTwoNodes)
@@ -279,6 +279,17 @@ func TestCreateCluster(t *testing.T) {
 			},
 			expectedErr: "number of operators is below minimum",
 		},
+		{
+			Name: "custom target gas limit",
+			Config: clusterConfig{
+				Name:           "test_cluster",
+				NumNodes:       4,
+				Threshold:      3,
+				NumDVs:         3,
+				Network:        eth2util.Holesky.Name,
+				TargetGasLimit: 36000000,
+			},
+		},
 	}
 
 	for _, test := range tests {
@@ -297,6 +308,9 @@ func TestCreateCluster(t *testing.T) {
 			test.Config.InsecureKeys = true
 			test.Config.WithdrawalAddrs = []string{zeroAddress}
 			test.Config.FeeRecipientAddrs = []string{zeroAddress}
+			if test.Config.TargetGasLimit == 0 && test.defFileProvider == nil {
+				test.Config.TargetGasLimit = 30000000
+			}
 
 			if test.Prep != nil {
 				test.Config = test.Prep(t, test.Config)
@@ -417,11 +431,12 @@ func testCreateCluster(t *testing.T, conf clusterConfig, def cluster.Definition,
 func TestValidateDef(t *testing.T) {
 	ctx := context.Background()
 	conf := clusterConfig{
-		Name:      "test",
-		NumNodes:  4,
-		NumDVs:    4,
-		Threshold: 3,
-		Network:   "goerli",
+		Name:           "test",
+		NumNodes:       4,
+		NumDVs:         4,
+		Threshold:      3,
+		TargetGasLimit: 30000000,
+		Network:        eth2util.Goerli.Name,
 	}
 
 	for range conf.NumDVs {
@@ -568,6 +583,7 @@ func TestSplitKeys(t *testing.T) {
 			test.conf.SplitKeys = true
 			test.conf.InsecureKeys = true
 			test.conf.Network = eth2util.Goerli.Name
+			test.conf.TargetGasLimit = 30000000
 
 			var buf bytes.Buffer
 			err = runCreateCluster(context.Background(), &buf, test.conf)
@@ -640,6 +656,90 @@ func TestMultipleAddresses(t *testing.T) {
 	})
 }
 
+func TestTargetGasLimit(t *testing.T) {
+	tests := []struct {
+		name                   string
+		conf                   clusterConfig
+		expectedTargetGasLimit uint
+		expectedErrMsg         string
+	}{
+		{
+			name: "target gas limit from unsupported version",
+			conf: clusterConfig{
+				DefFile:    "../cluster/examples/cluster-definition-005.json",
+				ClusterDir: t.TempDir(),
+				NumNodes:   4,
+				Network:    defaultNetwork,
+			},
+			expectedTargetGasLimit: 0,
+		},
+		{
+			name: "target gas limit from supported version",
+			conf: clusterConfig{
+				DefFile:    "../cluster/examples/cluster-definition-006.json",
+				ClusterDir: t.TempDir(),
+				NumNodes:   4,
+				Network:    defaultNetwork,
+			},
+			expectedTargetGasLimit: 30000000,
+		},
+		{
+			name: "target gas limit with default version",
+			conf: clusterConfig{
+				Name:              t.Name(),
+				ClusterDir:        t.TempDir(),
+				NumNodes:          4,
+				Threshold:         3,
+				NumDVs:            1,
+				Network:           defaultNetwork,
+				WithdrawalAddrs:   []string{zeroAddress},
+				FeeRecipientAddrs: []string{zeroAddress},
+				InsecureKeys:      true,
+				TargetGasLimit:    36000000,
+			},
+			expectedTargetGasLimit: 36000000,
+		},
+		{
+			name: "no target gas limit with default version",
+			conf: clusterConfig{
+				Name:              t.Name(),
+				ClusterDir:        t.TempDir(),
+				NumNodes:          4,
+				Threshold:         3,
+				NumDVs:            1,
+				Network:           defaultNetwork,
+				WithdrawalAddrs:   []string{zeroAddress},
+				FeeRecipientAddrs: []string{zeroAddress},
+				InsecureKeys:      true,
+			},
+			expectedErrMsg: "target gas limit should be set",
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			var buf bytes.Buffer
+			err := runCreateCluster(context.Background(), &buf, test.conf)
+			if test.expectedErrMsg != "" {
+				require.ErrorContains(t, err, test.expectedErrMsg)
+			} else {
+				testutil.RequireNoError(t, err)
+
+				// Since `cluster-lock.json` is copied into each node directory, use any one of them.
+				b, err := os.ReadFile(path.Join(nodeDir(test.conf.ClusterDir, 0), "cluster-lock.json"))
+				require.NoError(t, err)
+
+				var lock cluster.Lock
+				require.NoError(t, json.Unmarshal(b, &lock))
+				require.NoError(t, lock.VerifyHashes())
+				require.NoError(t, lock.VerifySignatures())
+
+				require.Equal(t, test.expectedTargetGasLimit, lock.TargetGasLimit)
+			}
+		})
+	}
+}
+
 // TestKeymanager tests keymanager support by letting create cluster command split a single secret and then receiving those keyshares using test
 // keymanager servers. These shares are then combined to create the combined share which is then compared to the original secret that was split.
 func TestKeymanager(t *testing.T) {
@@ -683,6 +783,7 @@ func TestKeymanager(t *testing.T) {
 		SplitKeys:            true,
 		NumNodes:             minNodes,
 		Threshold:            minThreshold,
+		TargetGasLimit:       30000000,
 		KeymanagerAddrs:      addrs,
 		KeymanagerAuthTokens: authTokens,
 		Network:              eth2util.Goerli.Name,
@@ -766,6 +867,7 @@ func TestPublish(t *testing.T) {
 		NumNodes:          minNodes,
 		Threshold:         minThreshold,
 		NumDVs:            1,
+		TargetGasLimit:    30000000,
 		Network:           eth2util.Goerli.Name,
 		WithdrawalAddrs:   []string{zeroAddress},
 		FeeRecipientAddrs: []string{zeroAddress},
diff --git a/cmd/createdkg_internal_test.go b/cmd/createdkg_internal_test.go
index c1a9dcfc..a94bada7 100644
--- a/cmd/createdkg_internal_test.go
+++ b/cmd/createdkg_internal_test.go
@@ -30,6 +30,7 @@ func TestCreateDkgValid(t *testing.T) {
 		DKGAlgo:           "default",
 		DepositAmounts:    []int{8, 16, 4, 4},
 		ConsensusProtocol: "qbft",
+		TargetGasLimit:    30000000,
 		OperatorENRs: []string{
 			"enr:-JG4QFI0llFYxSoTAHm24OrbgoVx77dL6Ehl1Ydys39JYoWcBhiHrRhtGXDTaygWNsEWFb1cL7a1Bk0klIdaNuXplKWGAYGv0Gt7gmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL6bcis0tFXnbqG4KuywxT5BLhtmijPFApKCDJNl3mXFYN0Y3CCDhqDdWRwgg4u",
 			"enr:-JG4QPnqHa7FU3PBqGxpV5L0hjJrTUqv8Wl6_UTHt-rELeICWjvCfcVfwmax8xI_eJ0ntI3ly9fgxAsmABud6-yBQiuGAYGv0iYPgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMLLCMZ5Oqi_sdnBfdyhmysZMfFm78PgF7Y9jitTJPSroN0Y3CCPoODdWRwgj6E",
diff --git a/cmd/testdata/TestCreateCluster_custom_target_gas_limit_files.golden b/cmd/testdata/TestCreateCluster_custom_target_gas_limit_files.golden
new file mode 100644
index 00000000..153b9253
--- /dev/null
+++ b/cmd/testdata/TestCreateCluster_custom_target_gas_limit_files.golden
@@ -0,0 +1,22 @@
+[
+ "node0",
+ "node1",
+ "node2",
+ "node3",
+ "node0/charon-enr-private-key",
+ "node0/cluster-lock.json",
+ "node0/deposit-data.json",
+ "node0/validator_keys",
+ "node1/charon-enr-private-key",
+ "node1/cluster-lock.json",
+ "node1/deposit-data.json",
+ "node1/validator_keys",
+ "node2/charon-enr-private-key",
+ "node2/cluster-lock.json",
+ "node2/deposit-data.json",
+ "node2/validator_keys",
+ "node3/charon-enr-private-key",
+ "node3/cluster-lock.json",
+ "node3/deposit-data.json",
+ "node3/validator_keys"
+]
\ No newline at end of file
diff --git a/cmd/testdata/TestCreateCluster_custom_target_gas_limit_output.golden b/cmd/testdata/TestCreateCluster_custom_target_gas_limit_output.golden
new file mode 100644
index 00000000..da2d5e3d
--- /dev/null
+++ b/cmd/testdata/TestCreateCluster_custom_target_gas_limit_output.golden
@@ -0,0 +1,11 @@
+Created charon cluster:
+ --split-existing-keys=false
+
+charon/
+├─ node[0-3]/			Directory for each node
+│  ├─ charon-enr-private-key	Charon networking private key for node authentication
+│  ├─ cluster-lock.json		Cluster lock defines the cluster lock file which is signed by all nodes
+│  ├─ deposit-data-*.json	Deposit data files are used to activate a Distributed Validator on the DV Launchpad
+│  ├─ validator_keys		Validator keystores and password
+│  │  ├─ keystore-*.json	Validator private share key for duty signing
+│  │  ├─ keystore-*.txt		Keystore password files for keystore-*.json
diff --git a/cmd/testdata/Test_viewClusterManifest.golden b/cmd/testdata/Test_viewClusterManifest.golden
index 0d6d1eca..1c91e7b8 100644
--- a/cmd/testdata/Test_viewClusterManifest.golden
+++ b/cmd/testdata/Test_viewClusterManifest.golden
@@ -1,8 +1,8 @@
 {
  "dkg_algorithm": "default",
  "fork_version": "0x00001020",
- "initial_mutation_hash": "0xa308b53642d9a244f40aac844e31cd8e4a3bdfb6f701d930195113748dacefeb",
- "latest_mutation_hash": "0xa308b53642d9a244f40aac844e31cd8e4a3bdfb6f701d930195113748dacefeb",
+ "initial_mutation_hash": "0xe8183d11c7c648386b8e87fc5dbe61207a1b3a1581b191ecf76723da6d796ce5",
+ "latest_mutation_hash": "0xe8183d11c7c648386b8e87fc5dbe61207a1b3a1581b191ecf76723da6d796ce5",
  "name": "test cluster",
  "operators": [
   {
diff --git a/core/validatorapi/validatorapi_internal_test.go b/core/validatorapi/validatorapi_internal_test.go
index 1d5ceda6..990c5acc 100644
--- a/core/validatorapi/validatorapi_internal_test.go
+++ b/core/validatorapi/validatorapi_internal_test.go
@@ -31,7 +31,7 @@ func TestMismatchKeysFunc(t *testing.T) {
 	t.Run("no mismatch", func(t *testing.T) {
 		allPubSharesByKey := map[core.PubKey]map[int]tbls.PublicKey{corePubKey: {shareIdx: pubkey}} // Maps self to self since not tbls
 
-		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, defaultGasLimit, nil)
 		require.NoError(t, err)
 		pk, err := vapi.getPubKeyFunc(eth2Pubkey)
 		require.NoError(t, err)
@@ -47,7 +47,7 @@ func TestMismatchKeysFunc(t *testing.T) {
 		pubshare := *(*tbls.PublicKey)(pkb)
 		allPubSharesByKey := map[core.PubKey]map[int]tbls.PublicKey{corePubKey: {shareIdx: pubkey, shareIdx + 1: pubshare}}
 
-		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, defaultGasLimit, nil)
 		require.NoError(t, err)
 
 		resp, err := vapi.getPubKeyFunc(eth2p0.BLSPubKey(pubshare)) // Ask for a mismatching key
@@ -65,7 +65,7 @@ func TestMismatchKeysFunc(t *testing.T) {
 		pubshare := eth2p0.BLSPubKey(pk)
 		allPubSharesByKey := map[core.PubKey]map[int]tbls.PublicKey{corePubKey: {shareIdx: pubkey}}
 
-		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := NewComponent(nil, allPubSharesByKey, shareIdx, nil, false, defaultGasLimit, nil)
 		require.NoError(t, err)
 
 		_, err = vapi.getPubKeyFunc(pubshare) // Ask for a mismatching key
diff --git a/core/validatorapi/validatorapi_test.go b/core/validatorapi/validatorapi_test.go
index d5304b49..1a03ef0d 100644
--- a/core/validatorapi/validatorapi_test.go
+++ b/core/validatorapi/validatorapi_test.go
@@ -192,7 +192,7 @@ func TestSubmitAttestations_Verify(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	vapi.RegisterPubKeyByAttestation(func(ctx context.Context, slot, commIdx, valCommIdx uint64) (core.PubKey, error) {
@@ -300,7 +300,7 @@ func TestSignAndVerify(t *testing.T) {
 	allPubSharesByKey := map[core.PubKey]map[int]tbls.PublicKey{corePubKey: {shareIdx: pubkey}} // Maps self to self since not tbls
 
 	// Setup validatorapi component.
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 	vapi.RegisterPubKeyByAttestation(func(context.Context, uint64, uint64, uint64) (core.PubKey, error) {
 		return core.PubKeyFromBytes(pubkey[:])
@@ -436,7 +436,7 @@ func TestComponent_SubmitProposalsWithWrongVCData(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	t.Run("full block fails", func(t *testing.T) {
@@ -534,7 +534,7 @@ func TestComponent_SubmitProposal(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned beacon block
@@ -628,7 +628,7 @@ func TestComponent_SubmitProposal_Gnosis(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned beacon block
@@ -725,7 +725,7 @@ func TestComponent_SubmitProposalInvalidSignature(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned beacon block
@@ -794,7 +794,7 @@ func TestComponent_SubmitProposalInvalidBlock(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	vapi.RegisterGetDutyDefinition(func(ctx context.Context, duty core.Duty) (core.DutyDefinitionSet, error) {
@@ -919,7 +919,7 @@ func TestComponent_SubmitBlindedProposal(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned beacon block
@@ -1009,7 +1009,7 @@ func TestComponent_SubmitBlindedProposalInvalidSignature(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned beacon block
@@ -1083,7 +1083,7 @@ func TestComponent_SubmitBlindedProposalInvalidBlock(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, 30000000, nil)
 	require.NoError(t, err)
 
 	vapi.RegisterGetDutyDefinition(func(ctx context.Context, duty core.Duty) (core.DutyDefinitionSet, error) {
@@ -1211,7 +1211,7 @@ func TestComponent_SubmitVoluntaryExit(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// Prepare unsigned voluntary exit
@@ -1281,7 +1281,7 @@ func TestComponent_SubmitVoluntaryExitInvalidSignature(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// Register subscriber
@@ -1337,7 +1337,7 @@ func TestComponent_Duties(t *testing.T) {
 		}
 
 		// Construct the validator api component
-		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 		require.NoError(t, err)
 
 		opts := &eth2api.ProposerDutiesOpts{
@@ -1363,7 +1363,7 @@ func TestComponent_Duties(t *testing.T) {
 		}
 
 		// Construct the validator api component
-		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 		require.NoError(t, err)
 
 		opts := &eth2api.AttesterDutiesOpts{
@@ -1389,7 +1389,7 @@ func TestComponent_Duties(t *testing.T) {
 		}
 
 		// Construct the validator api component
-		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+		vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 		require.NoError(t, err)
 
 		opts := &eth2api.SyncCommitteeDutiesOpts{
@@ -1425,7 +1425,7 @@ func TestComponent_SubmitValidatorRegistration(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, 30000000, nil)
 	require.NoError(t, err)
 
 	unsigned := testutil.RandomValidatorRegistration(t)
@@ -1503,7 +1503,7 @@ func TestComponent_SubmitValidatorRegistrationInvalidSignature(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, true, 30000000, nil)
 	require.NoError(t, err)
 
 	unsigned := testutil.RandomValidatorRegistration(t)
@@ -1558,7 +1558,7 @@ func TestComponent_TekuProposerConfig(t *testing.T) {
 	// Construct the validator api component
 	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, func(core.PubKey) string {
 		return feeRecipient
-	}, true, nil)
+	}, true, 30000000, nil)
 	require.NoError(t, err)
 
 	resp, err := vapi.ProposerConfig(ctx)
@@ -1727,7 +1727,7 @@ func TestComponent_SubmitAggregateAttestationVerify(t *testing.T) {
 	}
 
 	// Construct the validator api component
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	done := make(chan struct{})
@@ -1859,7 +1859,7 @@ func TestComponent_SubmitSyncCommitteeContributionsVerify(t *testing.T) {
 	}
 
 	// Construct validatorapi component.
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	done := make(chan struct{})
@@ -1941,7 +1941,7 @@ func TestComponent_ValidatorCache(t *testing.T) {
 		}
 	}
 
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, 1, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, 1, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	// request validators that are completely cached
@@ -2013,7 +2013,7 @@ func TestComponent_GetAllValidators(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct validatorapi component.
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	opts := &eth2api.ValidatorsOpts{
@@ -2050,7 +2050,7 @@ func TestComponent_GetClusterValidatorsWithError(t *testing.T) {
 	require.NoError(t, err)
 
 	// Construct validatorapi component.
-	vapi, err := validatorapi.NewComponent(bmock, make(map[core.PubKey]map[int]tbls.PublicKey), shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, make(map[core.PubKey]map[int]tbls.PublicKey), shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	opts := &eth2api.ValidatorsOpts{
@@ -2127,7 +2127,7 @@ func TestComponent_AggregateSyncCommitteeSelectionsVerify(t *testing.T) {
 	}
 
 	// Construct the validator api component.
-	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, nil)
+	vapi, err := validatorapi.NewComponent(bmock, allPubSharesByKey, shareIdx, nil, false, 30000000, nil)
 	require.NoError(t, err)
 
 	vapi.RegisterAwaitAggSigDB(func(ctx context.Context, duty core.Duty, pubkey core.PubKey) (core.SignedData, error) {
diff --git a/dkg/dkg_test.go b/dkg/dkg_test.go
index 44c16181..2a74566f 100644
--- a/dkg/dkg_test.go
+++ b/dkg/dkg_test.go
@@ -42,6 +42,30 @@ import (
 	"github.com/obolnetwork/charon/testutil"
 )
 
+const (
+	v1_10 = "v1.10.0"
+	v1_9  = "v1.9.0"
+	v1_8  = "v1.8.0"
+	v1_7  = "v1.7.0"
+	v1_6  = "v1.6.0"
+	v1_5  = "v1.5.0"
+	v1_4  = "v1.4.0"
+	v1_3  = "v1.3.0"
+	v1_2  = "v1.2.0"
+	v1_1  = "v1.1.0"
+	v1_0  = "v1.0.0"
+)
+
+func isAnyVersion(version string, list ...string) bool {
+	for _, v := range list {
+		if version == v {
+			return true
+		}
+	}
+
+	return false
+}
+
 func TestDKG(t *testing.T) {
 	const (
 		nodes = 3
@@ -108,6 +132,11 @@ func TestDKG(t *testing.T) {
 			if test.version != "" {
 				opts = append(opts, cluster.WithVersion(test.version))
 			}
+			if isAnyVersion(test.version, v1_0, v1_1, v1_2, v1_3, v1_4, v1_5, v1_6, v1_7, v1_8, v1_9) {
+				opts = append(opts, func(d *cluster.Definition) { d.TargetGasLimit = 0 })
+			} else {
+				opts = append(opts, func(d *cluster.Definition) { d.TargetGasLimit = 30000000 })
+			}
 
 			seed := 1
 			random := rand.New(rand.NewSource(int64(seed)))