Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically deregister nodes from core with attestations #76

Merged
merged 11 commits into from
Mar 13, 2025
6 changes: 4 additions & 2 deletions pkg/core/common/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ func TestSignAndRecover(t *testing.T) {
require.Nil(t, err)

registerEvent := &core_proto.ValidatorRegistration{
Endpoint: "http://road-to-uninode.audius.co",
CometAddress: "12345",
CometAddress: "12345",
DelegateWallet: "0xabcdef",
EthBlock: 20202,
Power: 10,
}

eventBytes, err := proto.Marshal(registerEvent)
Expand Down
36 changes: 34 additions & 2 deletions pkg/core/common/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,18 @@ func SignedTxProtoIntoSignedTxOapi(tx *core_proto.SignedTransaction) *models.Pro
Signer: innerTx.ManageEntity.Signer,
Nonce: fmt.Sprint(innerTx.ManageEntity.Nonce),
}
case *core_proto.SignedTransaction_Attestation:
oapiTx.Attestation = &models.ProtocolAttestation{
Signatures: innerTx.Attestation.Signatures,
}
switch innerTx.Attestation.Body.(type) {
case *core_proto.Attestation_ValidatorRegistration:
oapiTx.Attestation.ValidatorRegistration = ValidatorRegistrationIntoOapi(innerTx.Attestation.GetValidatorRegistration())
case *core_proto.Attestation_ValidatorDeregistration:
oapiTx.Attestation.ValidatorDeregistration = ValidatorDeregistrationIntoOapi(innerTx.Attestation.GetValidatorDeregistration())
}
case *core_proto.SignedTransaction_ValidatorRegistration:
oapiTx.ValidatorRegistration = &models.ProtocolValidatorRegistration{
oapiTx.ValidatorRegistration = &models.ProtocolValidatorRegistrationLegacy{
CometAddress: innerTx.ValidatorRegistration.CometAddress,
Endpoint: innerTx.ValidatorRegistration.Endpoint,
EthBlock: innerTx.ValidatorRegistration.EthBlock,
Expand All @@ -57,7 +67,7 @@ func SignedTxProtoIntoSignedTxOapi(tx *core_proto.SignedTransaction) *models.Pro
PubKey: innerTx.ValidatorRegistration.PubKey,
}
case *core_proto.SignedTransaction_ValidatorDeregistration:
oapiTx.ValidatorDeregistration = &models.ProtocolValidatorDeregistration{
oapiTx.ValidatorDeregistration = &models.ProtocolValidatorMisbehaviorDeregistration{
CometAddress: innerTx.ValidatorDeregistration.CometAddress,
PubKey: innerTx.ValidatorDeregistration.PubKey,
}
Expand All @@ -78,3 +88,25 @@ func SignedTxProtoIntoSignedTxOapi(tx *core_proto.SignedTransaction) *models.Pro

return oapiTx
}

func ValidatorRegistrationIntoOapi(vr *core_proto.ValidatorRegistration) *models.ProtocolValidatorRegistration {
return &models.ProtocolValidatorRegistration{
DelegateWallet: vr.DelegateWallet,
Endpoint: vr.Endpoint,
NodeType: vr.NodeType,
EthBlock: fmt.Sprint(vr.EthBlock),
SpID: vr.SpId,
CometAddress: vr.CometAddress,
Power: fmt.Sprint(vr.Power),
PubKey: vr.PubKey,
Deadline: fmt.Sprint(vr.Deadline),
}
}

func ValidatorDeregistrationIntoOapi(vr *core_proto.ValidatorDeregistration) *models.ProtocolValidatorDeregistration {
return &models.ProtocolValidatorDeregistration{
CometAddress: vr.CometAddress,
PubKey: vr.PubKey,
Deadline: fmt.Sprint(vr.Deadline),
}
}
49 changes: 49 additions & 0 deletions pkg/core/common/rendezvous.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package common

import (
"bytes"
"crypto/sha256"
"io"
"sort"
)

type NodeTuple struct {
addr string
score []byte
}

type NodeTuples []NodeTuple

func (s NodeTuples) Len() int { return len(s) }
func (s NodeTuples) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s NodeTuples) Less(i, j int) bool {
c := bytes.Compare(s[i].score, s[j].score)
if c == 0 {
return s[i].addr < s[j].addr
}
return c == -1
}

// Returns the first `size` number of addresses from a list of all validators sorted
// by a hashing function. The hashing is seeded according to the given key.
func GetAttestorRendezvous(validatorAddresses []string, key []byte, size int) map[string]bool {
tuples := make(NodeTuples, len(validatorAddresses))

hasher := sha256.New()
for i, addr := range validatorAddresses {
hasher.Reset()
io.WriteString(hasher, addr)
hasher.Write(key)
tuples[i] = NodeTuple{addr, hasher.Sum(nil)}
}
sort.Sort(tuples)
result := make(map[string]bool, len(validatorAddresses))
bound := min(len(tuples), size)
for i, tup := range tuples {
if i >= bound {
break
}
result[tup.addr] = true
}
return result
}
15 changes: 15 additions & 0 deletions pkg/core/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ type Config struct {
CometModule bool
PprofModule bool

/* Attestation Thresholds */
AttRegistrationMin int // minimum number of attestations needed to register a new node
AttRegistrationRSize int // rendezvous size for registration attestations (should be >= to AttRegistrationMin)
AttDeregistrationMin int // minimum number of attestations needed to deregister a node
AttDeregistrationRSize int // rendezvous size for deregistration attestations (should be >= to AttDeregistrationMin)
LegacyRegistrationCutoff int64 // Blocks after this height cannot register using the legacy tx (remove after next chain rollover)

/* Feature Flags */
EnablePoS bool
}
Expand Down Expand Up @@ -146,6 +153,11 @@ func ReadConfig(logger *common.Logger) (*Config, error) {
cfg.RetainHeight = int64(getEnvIntWithDefault("retainHeight", 604800))
cfg.Archive = GetEnvWithDefault("archive", "false") == "true"

cfg.AttRegistrationMin = 5
cfg.AttRegistrationRSize = 10
cfg.AttDeregistrationMin = 5
cfg.AttDeregistrationRSize = 10

// check if discovery specific key is set
isDiscovery := os.Getenv("audius_delegate_private_key") != ""
var delegatePrivateKey string
Expand Down Expand Up @@ -196,6 +208,7 @@ func ReadConfig(logger *common.Logger) (*Config, error) {
cfg.SlaRollupInterval = mainnetRollupInterval
cfg.ValidatorVotingPower = mainnetValidatorVotingPower
cfg.EnablePoS = true
cfg.LegacyRegistrationCutoff = 3000000 // delete after chain rollover

case "stage", "staging", "testnet":
cfg.PersistentPeers = GetEnvWithDefault("persistentPeers", moduloPersistentPeers(ethAddress, StagePersistentPeers, 3))
Expand All @@ -206,6 +219,7 @@ func ReadConfig(logger *common.Logger) (*Config, error) {
cfg.SlaRollupInterval = testnetRollupInterval
cfg.ValidatorVotingPower = testnetValidatorVotingPower
cfg.EnablePoS = true
cfg.LegacyRegistrationCutoff = 5000000 // delete after chain rollover

case "dev", "development", "devnet", "local", "sandbox":
cfg.PersistentPeers = GetEnvWithDefault("persistentPeers", DevPersistentPeers)
Expand All @@ -220,6 +234,7 @@ func ReadConfig(logger *common.Logger) (*Config, error) {
cfg.SlaRollupInterval = devnetRollupInterval
cfg.ValidatorVotingPower = devnetValidatorVotingPower
cfg.EnablePoS = true
cfg.LegacyRegistrationCutoff = 0
}

// Disable ssl for local postgres db connection
Expand Down
25 changes: 25 additions & 0 deletions pkg/core/db/reads.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions pkg/core/db/sql/reads.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ select *
from core_validators
order by comet_address;

-- name: GetAllEthAddressesOfRegisteredNodes :many
select eth_address
from core_validators;

-- name: GetNodeByEndpoint :one
select *
from core_validators
Expand Down
78 changes: 78 additions & 0 deletions pkg/core/gen/core_openapi/protocol/protocol_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading