Skip to content

Commit

Permalink
Merge pull request #7 from Layr-Labs/enable-single-update
Browse files Browse the repository at this point in the history
Enable a single update
  • Loading branch information
ian-shim authored Feb 13, 2024
2 parents 56f8a4c + ed29620 commit 00b4678
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 11 deletions.
13 changes: 9 additions & 4 deletions avssync.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ func (a *AvsSync) Start() {
a.logger.Infof("Starting avs sync with sleepBeforeFirstSyncDuration=%s, syncInterval=%s, operators=%v, quorums=%v, fetchQuorumsDynamically=%v, readerTimeoutDuration=%s, writerTimeoutDuration=%s",
a.sleepBeforeFirstSyncDuration, a.syncInterval, a.operators, a.quorums, a.fetchQuorumsDynamically, a.readerTimeoutDuration, a.writerTimeoutDuration)

// run something every syncInterval
ticker := time.NewTicker(a.syncInterval)
defer ticker.Stop()

// ticker doesn't tick immediately, so we send a first updateStakes here
// see https://github.com/golang/go/issues/17601
// we first sleep some amount of time before the first sync, which allows the syncs to happen at some preferred time
Expand All @@ -73,6 +69,15 @@ func (a *AvsSync) Start() {
a.logger.Error("Error updating stakes", err)
}

if a.syncInterval == 0 {
a.logger.Infof("Sync interval is 0, running updateStakes once and exiting")
return // only run once
}

// update stakes every syncInterval
ticker := time.NewTicker(a.syncInterval)
defer ticker.Stop()

for range ticker.C {
err := a.updateStakes()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var (
SyncIntervalFlag = cli.DurationFlag{
Name: "sync-interval",
Required: true,
Usage: "call updateStakes function at every `TIME` interval",
Usage: "Interval at which to sync with the chain (e.g. 24h). If set to 0, will only sync once and then exit.",
Value: 24 * time.Hour,
EnvVar: envVarPrefix + "SYNC_INTERVAL",
}
Expand Down
62 changes: 57 additions & 5 deletions integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func TestIntegrationUpdateSingleOperatorPath(t *testing.T) {
}
operatorAddr := crypto.PubkeyToAddress(operatorEcdsaPrivKey.PublicKey)
operatorBlsPrivKey := "0x1"
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{operatorAddr})
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{operatorAddr}, 30*time.Second)

// first register operator into avs. at this point, the operator will have whatever stake it had registered in eigenlayer in the avs
registerOperatorWithAvs(anvilHttpEndpoint, contractAddresses, operatorEcdsaPrivKeyHex, operatorBlsPrivKey)
Expand Down Expand Up @@ -117,7 +117,7 @@ func TestIntegrationFullOperatorSet(t *testing.T) {
}
operatorAddr := crypto.PubkeyToAddress(operatorEcdsaPrivKey.PublicKey)
operatorBlsPrivKey := "0x1"
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{})
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{}, 30*time.Second)

// first register operator into avs. at this point, the operator will have whatever stake it had registered in eigenlayer in the avs
registerOperatorWithAvs(anvilHttpEndpoint, contractAddresses, operatorEcdsaPrivKeyHex, operatorBlsPrivKey)
Expand Down Expand Up @@ -179,7 +179,7 @@ func TestIntegrationFullOperatorSetWithRetry(t *testing.T) {

// we create avs sync and replace its avsWriter with a mock that will fail the first 2 times we call UpdateStakesOfEntireOperatorSetForQuorums
// and succeed on the third time
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{})
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{}, 30*time.Second)
mockCtrl := gomock.NewController(t)
mockAvsRegistryWriter := chainiomocks.NewMockAvsRegistryWriter(mockCtrl)
// this is the test. we just make sure this is called 3 times
Expand All @@ -194,7 +194,59 @@ func TestIntegrationFullOperatorSetWithRetry(t *testing.T) {

}

func NewTestAvsSync(anvilHttpEndpoint string, contractAddresses ContractAddresses, operators []common.Address) *AvsSync {
func TestSingleRun(t *testing.T) {
/* Start the anvil chain */
anvilC := startAnvilTestContainer()
// Not sure why but deferring anvilC.Terminate() causes a panic when the test finishes...
// so letting it terminate silently for now
anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http")
if err != nil {
t.Fatal(err)
}

contractAddresses := getContractAddressesFromContractRegistry(anvilHttpEndpoint)
operatorEcdsaPrivKeyHex := "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
operatorEcdsaPrivKey, err := crypto.HexToECDSA(operatorEcdsaPrivKeyHex)
if err != nil {
t.Fatal(err)
}
operatorAddr := crypto.PubkeyToAddress(operatorEcdsaPrivKey.PublicKey)
operatorBlsPrivKey := "0x1"
// set sync interval to 0 so that we only run once
avsSync := NewTestAvsSync(anvilHttpEndpoint, contractAddresses, []common.Address{}, 0)

// first register operator into avs. at this point, the operator will have whatever stake it had registered in eigenlayer in the avs
registerOperatorWithAvs(anvilHttpEndpoint, contractAddresses, operatorEcdsaPrivKeyHex, operatorBlsPrivKey)

// get stake of operator before sync
operatorsPerQuorumBeforeSync, err := avsSync.avsReader.GetOperatorsStakeInQuorumsAtCurrentBlock(&bind.CallOpts{}, []byte{0})
if err != nil {
t.Fatal(err)
}
// TODO: should be checking all operators, not just the first one
operatorStakeBeforeSync := operatorsPerQuorumBeforeSync[0][0].Stake

// deposit into strategy to create a diff between eigenlayer and avs stakes
depositAmount := big.NewInt(100)
depositErc20IntoStrategyForOperator(anvilHttpEndpoint, contractAddresses.DelegationManager, contractAddresses.Erc20MockStrategy, operatorEcdsaPrivKeyHex, operatorAddr.Hex(), depositAmount)

avsSync.Start()

// get stake of operator after sync
operatorsPerQuorumAfterSync, err := avsSync.avsReader.GetOperatorsStakeInQuorumsAtCurrentBlock(&bind.CallOpts{}, []byte{0})
if err != nil {
t.Fatal(err)
}
operatorStakeAfterSync := operatorsPerQuorumAfterSync[0][0].Stake
operatorStakeDiff := new(big.Int).Sub(operatorStakeAfterSync, operatorStakeBeforeSync)

// we just check that the diff is equal to the deposited amount
if operatorStakeDiff.Cmp(depositAmount) != 0 {
t.Errorf("expected operator stake diff to be equal to deposit amount, got %v", operatorStakeDiff)
}
}

func NewTestAvsSync(anvilHttpEndpoint string, contractAddresses ContractAddresses, operators []common.Address, syncInterval time.Duration) *AvsSync {
logger, err := logging.NewZapLogger(logging.Development)
if err != nil {
panic(err)
Expand Down Expand Up @@ -252,7 +304,7 @@ func NewTestAvsSync(anvilHttpEndpoint string, contractAddresses ContractAddresse
avsReader,
avsWriter,
0*time.Second,
30*time.Second,
syncInterval,
operators,
// we only test with one quorum
[]byte{0},
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func avsSyncMain(cliCtx *cli.Context) error {
cliCtx.Duration(ReaderTimeoutDurationFlag.Name),
cliCtx.Duration(WriterTimeoutDurationFlag.Name),
)
avsSync.Start()

avsSync.Start()
return nil
}

0 comments on commit 00b4678

Please sign in to comment.