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

fix: add attribute nil verifications in chainReader #448

Merged
merged 26 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e9e320b
Add error returning in contract tests cases
maximopalopoli Jan 17, 2025
169625f
Add base structure of invalid config tests
maximopalopoli Jan 17, 2025
2c08047
Add test case and check in GetStakerShares
maximopalopoli Jan 17, 2025
d66567c
Add if verification and test case with GetDelegatedOperator
maximopalopoli Jan 17, 2025
c7cdca5
Improve variable name in test
maximopalopoli Jan 17, 2025
2aa773c
Fix make fmt check
maximopalopoli Jan 17, 2025
6604273
Add verification and test for GetNumOperatorSetsForOperator
maximopalopoli Jan 17, 2025
c89bd76
Add verification and test case for GetOperatorSetsForOperator
maximopalopoli Jan 17, 2025
5b8b6ac
Add test cases and verifications for IsOperatorRegisteredWithOperatorSet
maximopalopoli Jan 17, 2025
983614a
Add verification and test case for GetOperatorsForOperatorSet
maximopalopoli Jan 17, 2025
2e013f9
Add validation and test case for GetNumOperatorsForOperatorSet
maximopalopoli Jan 17, 2025
caf388d
Add validation and test case for GetStrategiesForOperatorSet
maximopalopoli Jan 17, 2025
2b4f3c8
Fix terminology in a comment
maximopalopoli Jan 17, 2025
4f0d591
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 17, 2025
f4f198a
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 20, 2025
7f2008a
Remove unused variables in TestInvalidConfig
maximopalopoli Jan 20, 2025
dec5afb
Add comment clarifying literal number
maximopalopoli Jan 20, 2025
e48948e
Remove unnecesary asserts
maximopalopoli Jan 20, 2025
57a4868
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 20, 2025
20deb64
test: `chainReader` shares and operatorSets functions (#437)
damiramirez Jan 20, 2025
1c28c33
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 20, 2025
40e2e49
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 21, 2025
168fc48
Merge branch 'dev' into add-attribute-null-verifications
maximopalopoli Jan 21, 2025
55bf665
unify TestInvalidConfig variants
maximopalopoli Jan 21, 2025
f495e8c
Increase timeout window
maximopalopoli Jan 21, 2025
306038e
Revert timeout window increase
maximopalopoli Jan 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions chainio/clients/elcontracts/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ func (r *ChainReader) GetStakerShares(
ctx context.Context,
stakerAddress gethcommon.Address,
) ([]gethcommon.Address, []*big.Int, error) {
if r.delegationManager == nil {
return nil, nil, errors.New("DelegationManager contract not provided")
}
return r.delegationManager.GetDepositedShares(&bind.CallOpts{Context: ctx}, stakerAddress)
}

Expand All @@ -125,6 +128,9 @@ func (r *ChainReader) GetDelegatedOperator(
stakerAddress gethcommon.Address,
blockNumber *big.Int,
) (gethcommon.Address, error) {
if r.delegationManager == nil {
return gethcommon.Address{}, errors.New("DelegationManager contract not provided")
}
return r.delegationManager.DelegatedTo(&bind.CallOpts{Context: ctx}, stakerAddress)
}

Expand Down Expand Up @@ -447,6 +453,9 @@ func (r *ChainReader) GetNumOperatorSetsForOperator(
ctx context.Context,
operatorAddress gethcommon.Address,
) (*big.Int, error) {
if r.allocationManager == nil {
return nil, errors.New("AllocationManager contract not provided")
}
opSets, err := r.allocationManager.GetAllocatedSets(&bind.CallOpts{Context: ctx}, operatorAddress)
if err != nil {
return nil, err
Expand All @@ -460,6 +469,9 @@ func (r *ChainReader) GetOperatorSetsForOperator(
ctx context.Context,
operatorAddress gethcommon.Address,
) ([]allocationmanager.OperatorSet, error) {
if r.allocationManager == nil {
return nil, errors.New("AllocationManager contract not provided")
}
// TODO: we're fetching max int64 operatorSets here. What's the practical limit for timeout by RPC? do we need to
// paginate?
return r.allocationManager.GetAllocatedSets(&bind.CallOpts{Context: ctx}, operatorAddress)
Expand All @@ -473,13 +485,20 @@ func (r *ChainReader) IsOperatorRegisteredWithOperatorSet(
) (bool, error) {
if operatorSet.Id == 0 {
// this is an M2 AVS
if r.avsDirectory == nil {
return false, errors.New("AVSDirectory contract not provided")
}

status, err := r.avsDirectory.AvsOperatorStatus(&bind.CallOpts{Context: ctx}, operatorSet.Avs, operatorAddress)
if err != nil {
return false, err
}

return status == 1, nil
} else {
if r.allocationManager == nil {
return false, errors.New("AllocationManager contract not provided")
}
registeredOperatorSets, err := r.allocationManager.GetRegisteredSets(&bind.CallOpts{Context: ctx}, operatorAddress)
if err != nil {
return false, err
Expand All @@ -503,6 +522,10 @@ func (r *ChainReader) GetOperatorsForOperatorSet(
if operatorSet.Id == 0 {
return nil, errLegacyAVSsNotSupported
} else {
if r.allocationManager == nil {
return nil, errors.New("AllocationManager contract not provided")
}

return r.allocationManager.GetMembers(&bind.CallOpts{Context: ctx}, operatorSet)
}
}
Expand All @@ -515,6 +538,10 @@ func (r *ChainReader) GetNumOperatorsForOperatorSet(
if operatorSet.Id == 0 {
return nil, errLegacyAVSsNotSupported
} else {
if r.allocationManager == nil {
return nil, errors.New("AllocationManager contract not provided")
}

return r.allocationManager.GetMemberCount(&bind.CallOpts{Context: ctx}, operatorSet)
}
}
Expand All @@ -528,6 +555,10 @@ func (r *ChainReader) GetStrategiesForOperatorSet(
if operatorSet.Id == 0 {
return nil, errLegacyAVSsNotSupported
} else {
if r.allocationManager == nil {
return nil, errors.New("AllocationManager contract not provided")
}

return r.allocationManager.GetStrategiesInOperatorSet(&bind.CallOpts{Context: ctx}, operatorSet)
}
}
Expand Down
183 changes: 181 additions & 2 deletions chainio/clients/elcontracts/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ func TestChainReader(t *testing.T) {
})

t.Run("get delegated operator", func(t *testing.T) {
val := big.NewInt(0)
blockNumber := big.NewInt(0)
address, err := read_clients.ElChainReader.GetDelegatedOperator(
ctx,
common.HexToAddress(operator.Address),
val,
blockNumber,
)

assert.NoError(t, err)
Expand Down Expand Up @@ -734,3 +734,182 @@ func TestAppointeesFunctions(t *testing.T) {
assert.NotEmpty(t, appointeesPermission)
})
}

func TestContractErrorCases(t *testing.T) {
ctx := context.Background()

testConfig := testutils.GetDefaultTestConfig()
anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName)
require.NoError(t, err)

anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http")
require.NoError(t, err)
contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint)

config := elcontracts.Config{
DelegationManagerAddress: contractAddrs.DelegationManager,
}

chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config)
require.NoError(t, err)

strategyAddr := common.HexToAddress("34634374736473673643")

t.Run("GetStrategyAndUnderlyingToken", func(t *testing.T) {
strategy, undToken, err := chainReader.GetStrategyAndUnderlyingToken(ctx, strategyAddr)
assert.Zero(t, strategy)
assert.Zero(t, undToken)
assert.Error(t, err)
assert.Equal(t, err.Error(), "Failed to fetch token contract: no contract code at given address")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we know that this function will throw an error, is it necessary to check the strategy and undToken?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

})

t.Run("GetStrategyAndUnderlyingERC20Token", func(t *testing.T) {
strategy, methods, undToken, err := chainReader.GetStrategyAndUnderlyingERC20Token(ctx, strategyAddr)
assert.Zero(t, strategy)
assert.Zero(t, methods)
assert.Zero(t, undToken)
assert.Error(t, err)
assert.Equal(t, err.Error(), "Failed to fetch token contract: no contract code at given address")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

})
}

// TestInvalidConfig tests the behavior of the chainReader when the config is invalid (e.g. missing addresses, wrong
// addresses)
func TestInvalidConfig(t *testing.T) {
testConfig := testutils.GetDefaultTestConfig()
anvilC, err := testutils.StartAnvilContainer(testConfig.AnvilStateFileName)
require.NoError(t, err)

anvilHttpEndpoint, err := anvilC.Endpoint(context.Background(), "http")
require.NoError(t, err)

contractAddrs := testutils.GetContractAddressesFromContractRegistry(anvilHttpEndpoint)

operatorAddr := testutils.ANVIL_FIRST_ADDRESS
operator := types.Operator{
Address: operatorAddr,
}

config := elcontracts.Config{}
chainReader, err := testclients.NewTestChainReaderFromConfig(anvilHttpEndpoint, config)
require.NoError(t, err)

_ = contractAddrs
_ = operator
_ = chainReader
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we going to use these variables? Otherwise we can remove them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


t.Run("try to get a staker shares with invalid config", func(t *testing.T) {
// GetStakerShares needs a correct DelegationManagerAddress
_, _, err := chainReader.GetStakerShares(context.Background(), common.HexToAddress(operator.Address))
require.Error(t, err)
})

t.Run("try to get the delegated operator shares with invalid config", func(t *testing.T) {
// GetDelegatedOperator needs a correct DelegationManagerAddress
_, err := chainReader.GetDelegatedOperator(
context.Background(),
common.HexToAddress(operator.Address),
big.NewInt(0),
)
require.Error(t, err)
})

t.Run("try to get the number of operator sets for an operator with invalid config", func(t *testing.T) {
// GetNumOperatorSetsForOperator needs a correct AllocationManagerAddress
_, err := chainReader.GetNumOperatorSetsForOperator(context.Background(), common.HexToAddress(operator.Address))
require.Error(t, err)
})

t.Run("try to get the operator sets for an operator with invalid config", func(t *testing.T) {
// GetOperatorSetsForOperator needs a correct AllocationManagerAddress
_, err := chainReader.GetOperatorSetsForOperator(context.Background(), common.HexToAddress(operator.Address))
require.Error(t, err)
})

t.Run("try to check if the operator is registered in an operator set with set id 0 and an invalid config",
func(t *testing.T) {
// IsOperatorRegisteredWithOperatorSet with setId 0 needs a correct AVSDirectory
testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS)
operatorSetId := uint32(0)
operatorSet := allocationmanager.OperatorSet{
Avs: testAddr,
Id: operatorSetId,
}
_, err := chainReader.IsOperatorRegisteredWithOperatorSet(
context.Background(),
common.HexToAddress(operator.Address),
operatorSet,
)
require.Error(t, err)
},
)

t.Run("try to check if the operator is registered in an operator set with set id 1 and an invalid config",
func(t *testing.T) {
// IsOperatorRegisteredWithOperatorSet with setId 1 needs a correct AllocationManagerAddress
testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS)
operatorSetId := uint32(1)
operatorSet := allocationmanager.OperatorSet{
Avs: testAddr,
Id: operatorSetId,
}
_, err := chainReader.IsOperatorRegisteredWithOperatorSet(
context.Background(),
common.HexToAddress(operator.Address),
operatorSet,
)
require.Error(t, err)
},
)

t.Run("try to get the operators for an operator set with set id 1 and an invalid config",
func(t *testing.T) {
// GetOperatorsForOperatorSet needs a correct AllocationManagerAddress
testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS)
operatorSetId := uint32(1)
operatorSet := allocationmanager.OperatorSet{
Avs: testAddr,
Id: operatorSetId,
}
_, err := chainReader.GetOperatorsForOperatorSet(
context.Background(),
operatorSet,
)
require.Error(t, err)
},
)

t.Run("try to get the number of operators for an operator set with set id 1 and an invalid config",
func(t *testing.T) {
// GetNumOperatorsForOperatorSet needs a correct AllocationManagerAddress
testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS)
operatorSetId := uint32(1)
operatorSet := allocationmanager.OperatorSet{
Avs: testAddr,
Id: operatorSetId,
}
_, err := chainReader.GetNumOperatorsForOperatorSet(
context.Background(),
operatorSet,
)
require.Error(t, err)
},
)

t.Run("try to get the strategies for an operator set with set id 1 and an invalid config",
func(t *testing.T) {
// GetStrategiesForOperatorSet needs a correct AllocationManagerAddress
testAddr := common.HexToAddress(testutils.ANVIL_FIRST_ADDRESS)
operatorSetId := uint32(1)
operatorSet := allocationmanager.OperatorSet{
Avs: testAddr,
Id: operatorSetId,
}
_, err := chainReader.GetStrategiesForOperatorSet(
context.Background(),
operatorSet,
)
require.Error(t, err)
},
)
}
Loading