Skip to content

Commit

Permalink
cluster: remove definition operator nonce and release v1.2 (#1018)
Browse files Browse the repository at this point in the history
Removes operator nonce from cluster definition v1.2 and releases it.

category: feature
ticket: #891
  • Loading branch information
corverroos authored Aug 23, 2022
1 parent 9d46693 commit d66662b
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 319 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.45.2
version: v1.48.0
only-new-issues: true

- name: notify failure
Expand Down
214 changes: 82 additions & 132 deletions cluster/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,165 +19,115 @@ import (
"encoding/json"
"fmt"
"math/rand"
"os"
"strings"
"testing"

"github.com/goccy/go-yaml"
"github.com/stretchr/testify/require"

"github.com/obolnetwork/charon/cluster"
"github.com/obolnetwork/charon/testutil"
)

//go:generate go test . -v -update
//go:generate go test . -v -update -clean

func TestEncode(t *testing.T) {
rand.Seed(1)

definition := cluster.NewDefinition(
"test definition",
2,
3,
testutil.RandomETHAddress(),
testutil.RandomETHAddress(),
"0x00000002",
[]cluster.Operator{
{
Address: testutil.RandomETHAddress(),
ENR: fmt.Sprintf("enr://%x", testutil.RandomBytes32()),
Nonce: 0,
ConfigSignature: testutil.RandomBytes32(),
ENRSignature: testutil.RandomBytes32(),
},
{
Address: testutil.RandomETHAddress(),
ENR: fmt.Sprintf("enr://%x", testutil.RandomBytes32()),
Nonce: 1,
ConfigSignature: testutil.RandomBytes32(),
ENRSignature: testutil.RandomBytes32(),
},
},
rand.New(rand.NewSource(0)),
)
definition.Timestamp = "2022-07-19T18:19:58+02:00" // Make deterministic

t.Run("definition_yaml", func(t *testing.T) {
jsonBytes, err := json.Marshal(definition)
require.NoError(t, err)
yamlBytes, err := yaml.JSONToYAML(jsonBytes)
require.NoError(t, err)
testutil.RequireGoldenBytes(t, yamlBytes)
})

t.Run("definition_json", func(t *testing.T) {
testutil.RequireGoldenJSON(t, definition)
})

hash1, err := definition.HashTreeRoot()
require.NoError(t, err)
hash2, err := definition.HashTreeRoot()
require.NoError(t, err)
require.Equal(t, hash1, hash2)

b1, err := json.Marshal(definition)
require.NoError(t, err)

var definition2 cluster.Definition
err = json.Unmarshal(b1, &definition2)
require.NoError(t, err)

b2, err := json.Marshal(definition2)
require.NoError(t, err)

require.Equal(t, b1, b2)
require.Equal(t, definition, definition2)

lock := cluster.Lock{
Definition: definition,
SignatureAggregate: testutil.RandomBytes32(),
Validators: []cluster.DistValidator{
{
PubKey: testutil.RandomETHAddress(),
PubShares: [][]byte{
testutil.RandomBytes32(),
testutil.RandomBytes32(),
for _, version := range cluster.SupportedVersionsForT(t) {
vStr := strings.ReplaceAll(version, ".", "_")
rand.Seed(1)

definition := cluster.NewDefinition(
"test definition",
2,
3,
testutil.RandomETHAddress(),
testutil.RandomETHAddress(),
"0x00000002",
[]cluster.Operator{
{
Address: testutil.RandomETHAddress(),
ENR: fmt.Sprintf("enr://%x", testutil.RandomBytes32()),
ConfigSignature: testutil.RandomBytes32(),
ENRSignature: testutil.RandomBytes32(),
},
}, {
PubKey: testutil.RandomETHAddress(),
PubShares: [][]byte{
testutil.RandomBytes32(),
testutil.RandomBytes32(),
{
Address: testutil.RandomETHAddress(),
ENR: fmt.Sprintf("enr://%x", testutil.RandomBytes32()),
ConfigSignature: testutil.RandomBytes32(),
ENRSignature: testutil.RandomBytes32(),
},
},
},
}

t.Run("lock_json", func(t *testing.T) {
testutil.RequireGoldenJSON(t, lock)
})
rand.New(rand.NewSource(0)),
)
definition.Version = version
definition.Timestamp = "2022-07-19T18:19:58+02:00" // Make deterministic

t.Run("definition_json_"+vStr, func(t *testing.T) {
testutil.RequireGoldenJSON(t, definition,
testutil.WithFilename("cluster_definition_"+vStr+".json"))
})

t.Run("lock_yaml", func(t *testing.T) {
jsonBytes, err := json.Marshal(lock)
hash1, err := definition.HashTreeRoot()
require.NoError(t, err)
yamlBytes, err := yaml.JSONToYAML(jsonBytes)
hash2, err := definition.HashTreeRoot()
require.NoError(t, err)
testutil.RequireGoldenBytes(t, yamlBytes)
})
require.Equal(t, hash1, hash2)

hash1, err = lock.HashTreeRoot()
require.NoError(t, err)
hash2, err = lock.HashTreeRoot()
require.NoError(t, err)
require.Equal(t, hash1, hash2)
b1, err := json.Marshal(definition)
require.NoError(t, err)

b1, err = json.Marshal(lock)
require.NoError(t, err)
var definition2 cluster.Definition
err = json.Unmarshal(b1, &definition2)
require.NoError(t, err)

var lock2 cluster.Lock
err = json.Unmarshal(b1, &lock2)
require.NoError(t, err)
b2, err := json.Marshal(definition2)
require.NoError(t, err)

b2, err = json.Marshal(lock2)
require.NoError(t, err)
require.Equal(t, b1, b2)
require.Equal(t, definition, definition2)

lock := cluster.Lock{
Definition: definition,
SignatureAggregate: testutil.RandomBytes32(),
Validators: []cluster.DistValidator{
{
PubKey: testutil.RandomETHAddress(),
PubShares: [][]byte{
testutil.RandomBytes32(),
testutil.RandomBytes32(),
},
}, {
PubKey: testutil.RandomETHAddress(),
PubShares: [][]byte{
testutil.RandomBytes32(),
testutil.RandomBytes32(),
},
},
},
}

require.Equal(t, b1, b2)
require.Equal(t, lock, lock2)
}
t.Run("_lock_json"+vStr, func(t *testing.T) {
testutil.RequireGoldenJSON(t, lock,
testutil.WithFilename("cluster_lock_"+vStr+".json"))
})

// TestBackwardsCompatability ensures that the current code is backwards compatible
// with previous versions stored in testdata.
func TestBackwardsCompatability(t *testing.T) {
tests := []struct {
version string
}{
{
version: "v1.0.0",
},
{
version: "v1.1.0",
},
{
version: "v1.2.0",
},
// Note: Add testdata files for newer versions when bumped.
}
for _, test := range tests {
t.Run(test.version, func(t *testing.T) {
suffix := strings.ReplaceAll(test.version, ".", "_")
hash1, err = lock.HashTreeRoot()
require.NoError(t, err)
hash2, err = lock.HashTreeRoot()
require.NoError(t, err)
require.Equal(t, hash1, hash2)

b, err := os.ReadFile(fmt.Sprintf("testdata/definition_%s.json", suffix))
require.NoError(t, err)
b1, err = json.Marshal(lock)
require.NoError(t, err)

var def cluster.Definition
require.NoError(t, json.Unmarshal(b, &def))
var lock2 cluster.Lock
err = json.Unmarshal(b1, &lock2)
require.NoError(t, err)

b, err = os.ReadFile(fmt.Sprintf("testdata/lock_%s.json", suffix))
require.NoError(t, err)
b2, err = json.Marshal(lock2)
require.NoError(t, err)

var lock cluster.Lock
require.NoError(t, json.Unmarshal(b, &lock))
})
require.Equal(t, b1, b2)
require.Equal(t, lock, lock2)
}
}

Expand Down
21 changes: 16 additions & 5 deletions cluster/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (d Definition) Verify() error {
}

// Check that we have a valid config signature for each operator.
digest, err := digestEIP712(o.Address, configHash[:], 0)
digest, err := digestEIP712(o.Address, configHash[:], zeroNonce)
if err != nil {
return err
}
Expand All @@ -143,7 +143,7 @@ func (d Definition) Verify() error {
}

// Check that we have a valid enr signature for each operator.
digest, err = digestEIP712(o.Address, []byte(o.ENR), 0)
digest, err = digestEIP712(o.Address, []byte(o.ENR), zeroNonce)
if err != nil {
return err
}
Expand Down Expand Up @@ -210,8 +210,14 @@ func (d Definition) HashTreeRootWith(hh ssz.HashWalker) error {
subIndx := hh.Index()
num := uint64(len(d.Operators))
for _, operator := range d.Operators {
if err := operator.HashTreeRootWith(hh); err != nil {
return err
if isJSONv1x1(d.Version) { // Initial operator struct versions had a zero nonce.
if err := operator.HashTreeRootWithV1x1(hh); err != nil {
return err
}
} else {
if err := operator.HashTreeRootWith(hh); err != nil {
return err
}
}
}
hh.MerkleizeWithMixin(subIndx, num, num)
Expand Down Expand Up @@ -396,6 +402,11 @@ func unmarshalDefinitionV1x1(data []byte) (def Definition, configHashJSON, defHa
return Definition{}, nil, nil, errors.Wrap(err, "unmarshal definition v1_1")
}

operators, err := operatorsFromV1x1(defJSON.Operators)
if err != nil {
return Definition{}, nil, nil, err
}

def = Definition{
Name: defJSON.Name,
UUID: defJSON.UUID,
Expand All @@ -407,7 +418,7 @@ func unmarshalDefinitionV1x1(data []byte) (def Definition, configHashJSON, defHa
WithdrawalAddress: defJSON.WithdrawalAddress,
DKGAlgorithm: defJSON.DKGAlgorithm,
ForkVersion: defJSON.ForkVersion,
Operators: operatorsFromV1x1(defJSON.Operators),
Operators: operators,
}

return def, defJSON.ConfigHash, defJSON.DefinitionHash, nil
Expand Down
Loading

0 comments on commit d66662b

Please sign in to comment.