From 13dfb49679b475ac2e600e64872d9f0acd32dcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20R=C3=B3=C5=BCa=C5=84ski?= Date: Wed, 31 Jul 2024 21:12:25 +0000 Subject: [PATCH] remove fixed oracle (#6196) ## Motivation it's not used anywhere --- eligibility/fixedoracle.go | 272 -------------------------------- eligibility/fixedoracle_test.go | 183 --------------------- 2 files changed, 455 deletions(-) delete mode 100644 eligibility/fixedoracle.go delete mode 100644 eligibility/fixedoracle_test.go diff --git a/eligibility/fixedoracle.go b/eligibility/fixedoracle.go deleted file mode 100644 index f73cc1b7fc..0000000000 --- a/eligibility/fixedoracle.go +++ /dev/null @@ -1,272 +0,0 @@ -// Package eligibility defines fixed size oracle used for node testing -package eligibility - -import ( - "context" - "encoding/binary" - "sync" - - "github.com/spacemeshos/go-scale" - - "github.com/spacemeshos/go-spacemesh/common/types" - "github.com/spacemeshos/go-spacemesh/hash" - "github.com/spacemeshos/go-spacemesh/log" - "github.com/spacemeshos/go-spacemesh/signing" -) - -// FixedRolacle is an eligibility simulator with pre-determined honest and faulty participants. -type FixedRolacle struct { - logger log.Log - - mutex sync.Mutex - mapRW sync.RWMutex - honest map[types.NodeID]struct{} - faulty map[types.NodeID]struct{} - emaps map[types.Hash32]map[types.NodeID]struct{} -} - -// New initializes the oracle with no participants. -func New(logger log.Log) *FixedRolacle { - return &FixedRolacle{ - logger: logger, - honest: make(map[types.NodeID]struct{}), - faulty: make(map[types.NodeID]struct{}), - emaps: make(map[types.Hash32]map[types.NodeID]struct{}), - } -} - -// IsIdentityActiveOnConsensusView is use to satisfy the API, currently always returns true. -func (fo *FixedRolacle) IsIdentityActiveOnConsensusView( - ctx context.Context, - edID types.NodeID, - layer types.LayerID, -) (bool, error) { - return true, nil -} - -// Export creates a map with the eligible participants for id and committee size. -func (fo *FixedRolacle) Export(id types.Hash32, committeeSize int) map[types.NodeID]struct{} { - fo.mapRW.RLock() - total := len(fo.honest) + len(fo.faulty) - fo.mapRW.RUnlock() - - // normalize committee size - size := committeeSize - if committeeSize > total { - fo.logger.With().Warning("committee size bigger than the number of clients", - log.Int("committee_size", committeeSize), - log.Int("num_clients", total)) - size = total - } - - fo.mapRW.Lock() - // generate if not exist for the requested K - if _, exist := fo.emaps[id]; !exist { - fo.emaps[id] = fo.generateEligibility(context.TODO(), size) - } - m := fo.emaps[id] - fo.mapRW.Unlock() - - return m -} - -func (fo *FixedRolacle) update(m map[types.NodeID]struct{}, client types.NodeID) { - fo.mutex.Lock() - - if _, exist := m[client]; exist { - fo.mutex.Unlock() - return - } - - m[client] = struct{}{} - - fo.mutex.Unlock() -} - -// Register adds a participant to the eligibility map. can be honest or faulty. -func (fo *FixedRolacle) Register(isHonest bool, client types.NodeID) { - if isHonest { - fo.update(fo.honest, client) - } else { - fo.update(fo.faulty, client) - } -} - -// Unregister removes a participant from the eligibility map. can be honest or faulty. -// TODO: just remove from both instead of specifying. -func (fo *FixedRolacle) Unregister(isHonest bool, client types.NodeID) { - fo.mutex.Lock() - if isHonest { - delete(fo.honest, client) - } else { - delete(fo.faulty, client) - } - fo.mutex.Unlock() -} - -func cloneMap(m map[types.NodeID]struct{}) map[types.NodeID]struct{} { - c := make(map[types.NodeID]struct{}, len(m)) - for k, v := range m { - c[k] = v - } - - return c -} - -func pickUnique(pickCount int, orig, dest map[types.NodeID]struct{}) { - i := 0 - for k := range orig { // randomly pass on clients - if i == pickCount { // pick exactly size - break - } - - dest[k] = struct{}{} - delete(orig, k) // unique pick - i++ - } -} - -func (fo *FixedRolacle) generateEligibility(ctx context.Context, expCom int) map[types.NodeID]struct{} { - logger := fo.logger.WithContext(ctx) - emap := make(map[types.NodeID]struct{}, expCom) - - if expCom == 0 { - return emap - } - - expHonest := expCom/2 + 1 - if expHonest > len(fo.honest) { - logger.With().Warning("not enough registered honest participants", - log.Int("expected", expHonest), - log.Int("actual", len(fo.honest))) - expHonest = len(fo.honest) - } - - hon := cloneMap(fo.honest) - pickUnique(expHonest, hon, emap) - - expFaulty := expCom - expHonest - if expFaulty > len(fo.faulty) { - if len(fo.faulty) > 0 { // not enough - logger.With().Debug("not enough registered dishonest participants to pick from, picking all faulty", - log.Int("expected", expFaulty), - log.Int("actual", len(fo.faulty))) - } else { // no faulty at all - acceptable - logger.Debug("no registered dishonest participants to pick from, picking honest instead") - } - expFaulty = len(fo.faulty) - } - - if expFaulty > 0 { // pick faulty if you need - fau := cloneMap(fo.faulty) - pickUnique(expFaulty, fau, emap) - } - - rem := expCom - expHonest - expFaulty - if rem > 0 { // need to pickUnique the remaining from honest - pickUnique(rem, hon, emap) - } - - return emap -} - -func hashLayerAndRound(logger log.Log, instanceID types.LayerID, round uint32) types.Hash32 { - kInBytes := make([]byte, 4) - binary.LittleEndian.PutUint32(kInBytes, round) - h := hash.GetHasher() - defer hash.PutHasher(h) - enc := scale.NewEncoder(h) - _, err := instanceID.EncodeScale(enc) - _, err2 := h.Write(kInBytes) - - if err != nil || err2 != nil { - logger.With().Error("errors trying to create a hash", - log.FieldNamed("err1", log.Err(err)), - log.FieldNamed("err2", log.Err(err2))) - } - return types.BytesToHash(h.Sum([]byte{})) -} - -// Validate is required to conform to the Rolacle interface, but should never be called. -func (fo *FixedRolacle) Validate( - context.Context, - types.LayerID, - uint32, - int, - types.NodeID, - types.VrfSignature, - uint16, -) (bool, error) { - panic("implement me!") -} - -// CalcEligibility returns 1 if the miner is eligible in given layer, and 0 otherwise. -func (fo *FixedRolacle) CalcEligibility( - ctx context.Context, - layer types.LayerID, - round uint32, - committeeSize int, - id types.NodeID, - sig types.VrfSignature, -) (uint16, error) { - eligible, err := fo.eligible(ctx, layer, round, committeeSize, id) - if eligible { - return 1, nil - } - return 0, err -} - -// eligible returns whether the specific NodeID is eligible for layer in round and committee size. -func (fo *FixedRolacle) eligible( - ctx context.Context, - layer types.LayerID, - round uint32, - committeeSize int, - id types.NodeID, -) (bool, error) { - fo.mapRW.RLock() - total := len(fo.honest) + len(fo.faulty) // safe since len >= 0 - fo.mapRW.RUnlock() - - // normalize committee size - size := committeeSize - if committeeSize > total { - fo.logger.WithContext(ctx).With().Warning("committee size bigger than the number of clients", - log.Int("committee_size", committeeSize), - log.Int("num_clients", total), - ) - size = total - } - - instID := hashLayerAndRound(fo.logger, layer, round) - - fo.mapRW.Lock() - // generate if not exist for the requested K - if _, exist := fo.emaps[instID]; !exist { - fo.emaps[instID] = fo.generateEligibility(ctx, size) - } - // get eligibility result - _, exist := fo.emaps[instID][id] - fo.mapRW.Unlock() - - return exist, nil -} - -// Proof generates a proof for the round. used to satisfy interface. -func (fo *FixedRolacle) Proof( - ctx context.Context, - _ *signing.VRFSigner, - layer types.LayerID, - round uint32, -) (types.VrfSignature, error) { - kInBytes := make([]byte, 4) - binary.LittleEndian.PutUint32(kInBytes, round) - h := hash.GetHasher() - defer hash.PutHasher(h) - if _, err := h.Write(kInBytes); err != nil { - fo.logger.WithContext(ctx).With().Error("error writing hash", log.Err(err)) - } - var proof types.VrfSignature - _, err := h.Digest().Read(proof[:]) - return proof, err -} diff --git a/eligibility/fixedoracle_test.go b/eligibility/fixedoracle_test.go deleted file mode 100644 index 8456b6501c..0000000000 --- a/eligibility/fixedoracle_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package eligibility - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/spacemeshos/go-spacemesh/common/types" - "github.com/spacemeshos/go-spacemesh/log/logtest" -) - -const ( - numOfClients = 100 -) - -func TestFixedRolacle_Eligible(t *testing.T) { - oracle := New(logtest.New(t)) - for i := 0; i < numOfClients-1; i++ { - oracle.Register(true, types.RandomNodeID()) - } - v := types.RandomNodeID() - oracle.Register(true, v) - - res, err := oracle.eligible(context.Background(), types.LayerID(1), 1, 10, v) - require.NoError(t, err) - res2, err := oracle.eligible(context.Background(), types.LayerID(1), 1, 10, v) - require.NoError(t, err) - require.Equal(t, res, res2) -} - -func TestFixedRolacle_Eligible2(t *testing.T) { - pubs := make([]types.NodeID, 0, numOfClients) - oracle := New(logtest.New(t)) - for i := 0; i < numOfClients; i++ { - s := types.RandomNodeID() - pubs = append(pubs, s) - oracle.Register(true, s) - } - - count := 0 - for _, p := range pubs { - res, _ := oracle.eligible(context.Background(), types.LayerID(1), 1, 10, p) - if res { - count++ - } - } - - assert.Equal(t, 10, count) - - count = 0 - for _, p := range pubs { - res, _ := oracle.eligible(context.Background(), types.LayerID(1), 1, 20, p) - if res { - count++ - } - } - - assert.Equal(t, 10, count) -} - -func TestFixedRolacle_Range(t *testing.T) { - oracle := New(logtest.New(t)) - pubs := make([]types.NodeID, 0, numOfClients) - for i := 0; i < numOfClients; i++ { - s := types.RandomNodeID() - pubs = append(pubs, s) - oracle.Register(true, s) - } - - count := 0 - for _, p := range pubs { - res, _ := oracle.eligible(context.Background(), types.LayerID(1), 1, numOfClients, p) - if res { - count++ - } - } - - // check all eligible - assert.Equal(t, numOfClients, count) - - count = 0 - for _, p := range pubs { - res, _ := oracle.eligible(context.Background(), types.LayerID(2), 1, 0, p) - if res { - count++ - } - } - - // check all not eligible - assert.Equal(t, 0, count) -} - -func TestFixedRolacle_Eligible3(t *testing.T) { - oracle := New(logtest.New(t)) - for i := 0; i < numOfClients/3; i++ { - s := types.RandomNodeID() - oracle.Register(true, s) - } - - for i := 0; i < 2*numOfClients/3; i++ { - s := types.RandomNodeID() - oracle.Register(false, s) - } - - exp := numOfClients / 2 - ok, err := oracle.eligible(context.Background(), types.LayerID(1), 1, exp, types.NodeID{1}) - require.NoError(t, err) - require.False(t, ok) - - hc := 0 - for k := range oracle.honest { - res, _ := oracle.eligible(context.Background(), types.LayerID(1), 1, exp, k) - if res { - hc++ - } - } - - dc := 0 - for k := range oracle.faulty { - res, _ := oracle.eligible(context.Background(), types.LayerID(1), 1, exp, k) - if res { - dc++ - } - } - - assert.Equal(t, exp/2+1, hc) - assert.Equal(t, exp/2-1, dc) -} - -func TestGenerateElibility(t *testing.T) { - oracle := New(logtest.New(t)) - ids := make([]types.NodeID, 0, 30) - for i := 0; i < 30; i++ { - s := types.RandomNodeID() - ids = append(ids, s) - oracle.Register(true, s) - } - - m := oracle.generateEligibility(context.Background(), len(oracle.honest)) - - for _, s := range ids { - _, ok := m[s] - require.True(t, ok) - } -} - -func TestFixedRolacle_Eligible4(t *testing.T) { - oracle := New(logtest.New(t)) - var ids []types.NodeID - for i := 0; i < 33; i++ { - s := types.RandomNodeID() - ids = append(ids, s) - oracle.Register(true, s) - } - - // when requesting a bigger committee size everyone should be eligible - - for _, s := range ids { - res, _ := oracle.eligible(context.Background(), 0, 1, numOfClients, s) - assert.True(t, res) - } -} - -func TestFixedRolacle_Export(t *testing.T) { - oracle := New(logtest.New(t)) - var ids []types.NodeID - for i := 0; i < 35; i++ { - s := types.RandomNodeID() - ids = append(ids, s) - oracle.Register(true, s) - } - - // when requesting a bigger committee size everyone should be eligible - - m := oracle.Export(types.RandomHash(), numOfClients) - - for _, s := range ids { - _, ok := m[s] - assert.True(t, ok) - } -}