Skip to content

Commit

Permalink
feat: implement sync of blocked senders with allowed
Browse files Browse the repository at this point in the history
  • Loading branch information
agparadiso committed Jan 19, 2024
1 parent f06fac7 commit 09e890b
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ contract FunctionsTermsOfServiceAllowList_GetBlockedSendersCount is FunctionsRou

s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS);
}

function test_GetBlockedSendersCount_Success() public {
// Send as stranger
vm.stopPrank();
Expand Down
107 changes: 81 additions & 26 deletions core/services/gateway/handlers/functions/allowlist/allowlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b
if err != nil {
return errors.Wrap(err, "unexpected error during functions_allow_list.NewTermsOfServiceAllowList")
}
allowedSenderList := make([]common.Address, 0)

var allowedSenderList []common.Address
if !a.config.StoreAllowedSendersEnabled {
allowedSenderList, err = tosContract.GetAllAllowedSenders(&bind.CallOpts{
Pending: false,
Expand All @@ -216,43 +216,98 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b
return errors.Wrap(err, "error calling GetAllAllowedSenders")
}
} else {
count, err := tosContract.GetAllowedSendersCount(&bind.CallOpts{
err = a.syncStoredAllowedAndBlockedSenders(ctx, tosContract, blockNum)
if err != nil {
return errors.Wrap(err, "failed to sync the stored allowed and blocked senders")
}

allowedSenderList, err = a.getAllowedSendersInRange(ctx, tosContract, blockNum)
if err != nil {
return errors.Wrap(err, "failed to get allowed senders in rage")
}
}

a.update(allowedSenderList)
return nil
}

func (a *onchainAllowlist) getAllowedSendersInRange(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) ([]common.Address, error) {
allowedSenderList := make([]common.Address, 0)
count, err := tosContract.GetAllowedSendersCount(&bind.CallOpts{
Pending: false,
BlockNumber: blockNum,
Context: ctx,
})
if err != nil {
return nil, errors.Wrap(err, "unexpected error during functions_allow_list.GetAllowedSendersCount")
}

throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second)
for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) {
<-throttleTicker.C

idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize)
if idxEnd >= count {
idxEnd = count - 1
}

allowedSendersBatch, err := tosContract.GetAllowedSendersInRange(&bind.CallOpts{
Pending: false,
BlockNumber: blockNum,
Context: ctx,
})
}, idxStart, idxEnd)
if err != nil {
return errors.Wrap(err, "unexpected error during functions_allow_list.GetAllowedSendersCount")
return nil, errors.Wrap(err, "error calling GetAllowedSendersInRange")
}

throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second)
for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) {
<-throttleTicker.C
allowedSenderList = append(allowedSenderList, allowedSendersBatch...)
err = a.orm.CreateAllowedSenders(allowedSendersBatch)
if err != nil {
a.lggr.Errorf("failed to update stored allowedSenderList: %w", err)
}
}
throttleTicker.Stop()

idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize)
if idxEnd >= count {
idxEnd = count - 1
}
return allowedSenderList, nil
}

allowedSendersBatch, err := tosContract.GetAllowedSendersInRange(&bind.CallOpts{
Pending: false,
BlockNumber: blockNum,
Context: ctx,
}, idxStart, idxEnd)
if err != nil {
return errors.Wrap(err, "error calling GetAllowedSendersInRange")
}
// syncStoredAllowedAndBlockedSenders fetches the list of blocked addresses from the contract in batches
// and removes the addresses from the functions_allowlist table if present
func (a *onchainAllowlist) syncStoredAllowedAndBlockedSenders(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) error {
count, err := tosContract.GetBlockedSendersCount(&bind.CallOpts{
Pending: false,
BlockNumber: blockNum,
Context: ctx,
})
if err != nil {
return errors.Wrap(err, "unexpected error during functions_allow_list.GetBlockedSendersCount")
}

allowedSenderList = append(allowedSenderList, allowedSendersBatch...)
err = a.orm.CreateAllowedSenders(allowedSendersBatch)
if err != nil {
a.lggr.Errorf("failed to update stored allowedSenderList: %w", err)
}
throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second)
for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) {
<-throttleTicker.C

idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize)
if idxEnd >= count {
idxEnd = count - 1
}

blockedSendersBatch, err := tosContract.GetBlockedSendersInRange(&bind.CallOpts{
Pending: false,
BlockNumber: blockNum,
Context: ctx,
}, idxStart, idxEnd)
if err != nil {
return errors.Wrap(err, "error calling GetAllowedSendersInRange")
}

err = a.orm.DeleteAllowedSenders(blockedSendersBatch)
if err != nil {
a.lggr.Errorf("failed to delete blocked address from allowed list in storage: %w", err)
}
throttleTicker.Stop()
}
throttleTicker.Stop()

a.update(allowedSenderList)
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func TestAllowlist_UpdateFromContract(t *testing.T) {
}

orm := amocks.NewORM(t)
orm.On("DeleteAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil)
orm.On("CreateAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil)

allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t))
Expand Down
25 changes: 25 additions & 0 deletions core/services/gateway/handlers/functions/allowlist/mocks/orm.go

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

32 changes: 32 additions & 0 deletions core/services/gateway/handlers/functions/allowlist/orm.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
type ORM interface {
GetAllowedSenders(offset, limit uint, qopts ...pg.QOpt) ([]common.Address, error)
CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error
DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error
}

type orm struct {
Expand Down Expand Up @@ -88,3 +89,34 @@ func (o *orm) CreateAllowedSenders(allowedSender []common.Address, qopts ...pg.Q

return nil
}

func (o *orm) DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error {
var valuesPlaceholder []string
for i := 1; i <= len(blockedSenders); i++ {
valuesPlaceholder = append(valuesPlaceholder, fmt.Sprintf("$%d", i+1))
}

stmt := fmt.Sprintf(`
DELETE FROM %s
WHERE router_contract_address = $1
AND allowed_address IN (%s);`, tableName, strings.Join(valuesPlaceholder, ", "))

args := []interface{}{o.routerContractAddress}
for _, bs := range blockedSenders {
args = append(args, bs)
}

res, err := o.q.WithOpts(qopts...).Exec(stmt, args...)
if err != nil {
return err
}

rowsAffected, err := res.RowsAffected()
if err != nil {
return err
}

o.lggr.Debugf("Successfully removed blocked senders from the allowed list: %s for routerContractAddress: %s. rowsAffected: %d", blockedSenders, o.routerContractAddress, rowsAffected)

return nil
}
51 changes: 51 additions & 0 deletions core/services/gateway/handlers/functions/allowlist/orm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,57 @@ func TestORM_CreateAllowedSenders(t *testing.T) {
})
}

func TestORM_DeleteAllowedSenders(t *testing.T) {
t.Parallel()

t.Run("OK-delete_blocked_sender_from_allowed_list", func(t *testing.T) {
orm, err := setupORM(t)
require.NoError(t, err)
add1 := testutils.NewAddress()
add2 := testutils.NewAddress()
add3 := testutils.NewAddress()
err = orm.CreateAllowedSenders([]common.Address{add1, add2, add3})
require.NoError(t, err)

results, err := orm.GetAllowedSenders(0, 10)
require.NoError(t, err)
require.Equal(t, 3, len(results), "incorrect results length")
require.Equal(t, add1, results[0])

err = orm.DeleteAllowedSenders([]common.Address{add1, add3})
require.NoError(t, err)

results, err = orm.GetAllowedSenders(0, 10)
require.NoError(t, err)
require.Equal(t, 1, len(results), "incorrect results length")
require.Equal(t, add2, results[0])
})

t.Run("OK-delete_non_existing_blocked_sender_from_allowed_list", func(t *testing.T) {
orm, err := setupORM(t)
require.NoError(t, err)
add1 := testutils.NewAddress()
add2 := testutils.NewAddress()
err = orm.CreateAllowedSenders([]common.Address{add1, add2})
require.NoError(t, err)

results, err := orm.GetAllowedSenders(0, 10)
require.NoError(t, err)
require.Equal(t, 2, len(results), "incorrect results length")
require.Equal(t, add1, results[0])

add3 := testutils.NewAddress()
err = orm.DeleteAllowedSenders([]common.Address{add3})
require.NoError(t, err)

results, err = orm.GetAllowedSenders(0, 10)
require.NoError(t, err)
require.Equal(t, 2, len(results), "incorrect results length")
require.Equal(t, add1, results[0])
require.Equal(t, add2, results[1])
})
}

func Test_NewORM(t *testing.T) {
t.Run("OK-create_ORM", func(t *testing.T) {
_, err := allowlist.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress())
Expand Down

0 comments on commit 09e890b

Please sign in to comment.