diff --git a/cluster/cluster_internal_test.go b/cluster/cluster_internal_test.go index d09fc89dd..7724e787f 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 e52a9b547..cc832b25e 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/definition.go b/cluster/definition.go index 402759d77..0f8e07e3e 100644 --- a/cluster/definition.go +++ b/cluster/definition.go @@ -64,7 +64,7 @@ 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") @@ -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 targetGasLimit != 0 && !supportTargetGasLimit(def.Version) { + return Definition{}, errors.New("the version does not support custom target gas limit", z.Str("version", def.Version)) + } + + if targetGasLimit == 0 && supportTargetGasLimit(def.Version) { + return Definition{}, errors.New("target gas limit should be set", z.Str("version", def.Version)) + } + return def.SetDefinitionHashes() } @@ -160,6 +169,9 @@ 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"` @@ -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 000000000..925d683c4 --- /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 b8998440f..22d97137c 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/ssz.go b/cluster/ssz.go index 3d9c1030c..715dcc205 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/test_cluster.go b/cluster/test_cluster.go index b31714f8d..b16c57abc 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 000000000..8b5579642 --- /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 000000000..d500947c8 --- /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/cluster/version.go b/cluster/version.go index cd36cc975..8dcfeda4f 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/createcluster.go b/cmd/createcluster.go index 14229f206..d372d03c8 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", 30000000, "Preferred target gas limit for transactions.") } func bindInsecureFlags(flags *pflag.FlagSet, insecureKeys *bool) { @@ -851,12 +854,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/createcluster_internal_test.go b/cmd/createcluster_internal_test.go index 46a09fc8d..ccc0dabdc 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.go b/cmd/createdkg.go index 41923d594..bcfd75cab 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", 30000000, "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/cmd/createdkg_internal_test.go b/cmd/createdkg_internal_test.go index c1a9dcfc6..a94bada79 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 000000000..153b92536 --- /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 000000000..da2d5e3d2 --- /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 0d6d1eca5..1c91e7b80 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": [ {