Skip to content
This repository has been archived by the owner on May 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #600 from keep-network/tbtc-optimizations
Browse files Browse the repository at this point in the history
TBTC extension optimizations

Here we add some TBTC extension optimizations that should reduce costs 
related to Ethereum integration. Specifically:

- We introduce a time cache for the monitoring filter. Determining whether a deposit 
should be tracked requires two ETH calls. This check is performed for each deposit 
multiple times as a response to monitored state transition events and all duplicates of
those events. This can result in a significant number of unnecessary ETH calls.
Introducing a time cache here should greatly reduce the number of calls.

- We implement a signer-based action delay factor. Currently, all monitoring signers act 
at the same time. As result, only the first transaction is always successful while the rest 
revert and burn some amount of gas. The change introduced here forces each signer to 
wait an additional time, according to its signer index, before acting. This should prevent
other signers to act if a successful action has been already made.
  • Loading branch information
pdyraga authored Nov 13, 2020
2 parents f660fff + 2e04da0 commit b658b02
Show file tree
Hide file tree
Showing 3 changed files with 340 additions and 44 deletions.
15 changes: 13 additions & 2 deletions pkg/chain/local/tbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type localChainLogger struct {
retrieveSignerPubkeyCalls int
provideRedemptionSignatureCalls int
increaseRedemptionFeeCalls int
keepAddressCalls int
}

func (lcl *localChainLogger) logRetrieveSignerPubkeyCall() {
Expand All @@ -64,14 +65,22 @@ func (lcl *localChainLogger) ProvideRedemptionSignatureCalls() int {
return lcl.provideRedemptionSignatureCalls
}

func (lcl *localChainLogger) logIncreaseRedemptionFeeCalls() {
func (lcl *localChainLogger) logIncreaseRedemptionFeeCall() {
lcl.increaseRedemptionFeeCalls++
}

func (lcl *localChainLogger) IncreaseRedemptionFeeCalls() int {
return lcl.increaseRedemptionFeeCalls
}

func (lcl *localChainLogger) logKeepAddressCall() {
lcl.keepAddressCalls++
}

func (lcl *localChainLogger) KeepAddressCalls() int {
return lcl.keepAddressCalls
}

type TBTCLocalChain struct {
*localChain

Expand Down Expand Up @@ -302,6 +311,8 @@ func (tlc *TBTCLocalChain) KeepAddress(depositAddress string) (string, error) {
tlc.tbtcLocalChainMutex.Lock()
defer tlc.tbtcLocalChainMutex.Unlock()

tlc.logger.logKeepAddressCall()

deposit, ok := tlc.deposits[depositAddress]
if !ok {
return "", fmt.Errorf("no deposit with address [%v]", depositAddress)
Expand Down Expand Up @@ -415,7 +426,7 @@ func (tlc *TBTCLocalChain) IncreaseRedemptionFee(
tlc.tbtcLocalChainMutex.Lock()
defer tlc.tbtcLocalChainMutex.Unlock()

tlc.logger.logIncreaseRedemptionFeeCalls()
tlc.logger.logIncreaseRedemptionFeeCall()

if _, exists := tlc.alwaysFailingTransactions["IncreaseRedemptionFee"]; exists {
return fmt.Errorf("always failing transaction")
Expand Down
125 changes: 106 additions & 19 deletions pkg/extensions/tbtc/tbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"sync"
"time"

"github.com/keep-network/keep-common/pkg/cache"

"github.com/ethereum/go-ethereum/common"

"github.com/ipfs/go-log"
Expand All @@ -24,9 +26,26 @@ import (
var logger = log.Logger("tbtc-extension")

const (
maxActAttempts = 3
pastEventsLookbackBlocks = 10000
// Maximum number of action attempts before giving up and returning
// a monitoring error.
maxActAttempts = 3

// Determines how many blocks from the past should be included
// during the past events lookup.
pastEventsLookbackBlocks = 10000

// Number of blocks which should elapse before confirming
// the given chain state expectations.
defaultBlockConfirmations = 12

// Determines how long the monitoring cache will maintain its entries about
// which deposits should be monitored by this client instance.
monitoringCachePeriod = 24 * time.Hour

// Used to calculate the action delay factor for the given signer index
// to avoid all signers executing the same action for deposit at the
// same time.
defaultSignerActionDelayStep = 5 * time.Minute
)

// TODO: Resume monitoring after client restart
Expand Down Expand Up @@ -80,15 +99,21 @@ func Initialize(ctx context.Context, chain chain.TBTCHandle) error {
}

type tbtc struct {
chain chain.TBTCHandle
monitoringLocks sync.Map
blockConfirmations uint64
chain chain.TBTCHandle
monitoringLocks sync.Map
blockConfirmations uint64
monitoredDepositsCache *cache.TimeCache
notMonitoredDepositsCache *cache.TimeCache
signerActionDelayStep time.Duration
}

func newTBTC(chain chain.TBTCHandle) *tbtc {
return &tbtc{
chain: chain,
blockConfirmations: defaultBlockConfirmations,
chain: chain,
blockConfirmations: defaultBlockConfirmations,
monitoredDepositsCache: cache.NewTimeCache(monitoringCachePeriod),
notMonitoredDepositsCache: cache.NewTimeCache(monitoringCachePeriod),
signerActionDelayStep: defaultSignerActionDelayStep,
}
}

Expand Down Expand Up @@ -141,6 +166,15 @@ func (t *tbtc) monitorRetrievePubKey(
return nil
}

timeoutFn := func(depositAddress string) (time.Duration, error) {
actionDelay, err := t.getSignerActionDelay(depositAddress)
if err != nil {
return 0, err
}

return timeout + actionDelay, nil
}

monitoringSubscription, err := t.monitorAndAct(
ctx,
"retrieve pubkey",
Expand All @@ -150,9 +184,7 @@ func (t *tbtc) monitorRetrievePubKey(
t.watchKeepClosed,
actFn,
actBackoffFn,
func(_ string) (time.Duration, error) {
return timeout, nil
},
timeoutFn,
)
if err != nil {
return err
Expand Down Expand Up @@ -313,6 +345,15 @@ func (t *tbtc) monitorProvideRedemptionSignature(
return nil
}

timeoutFn := func(depositAddress string) (time.Duration, error) {
actionDelay, err := t.getSignerActionDelay(depositAddress)
if err != nil {
return 0, err
}

return timeout + actionDelay, nil
}

monitoringSubscription, err := t.monitorAndAct(
ctx,
"provide redemption signature",
Expand All @@ -322,9 +363,7 @@ func (t *tbtc) monitorProvideRedemptionSignature(
t.watchKeepClosed,
actFn,
actBackoffFn,
func(_ string) (time.Duration, error) {
return timeout, nil
},
timeoutFn,
)
if err != nil {
return err
Expand Down Expand Up @@ -502,7 +541,12 @@ func (t *tbtc) monitorProvideRedemptionProof(
gotRedemptionSignatureTimestamp-redemptionRequestedTimestamp,
) * time.Second

return timeout - timeoutShift, nil
actionDelay, err := t.getSignerActionDelay(depositAddress)
if err != nil {
return 0, err
}

return (timeout - timeoutShift) + actionDelay, nil
}

monitoringSubscription, err := t.monitorAndAct(
Expand Down Expand Up @@ -761,23 +805,66 @@ func (t *tbtc) watchKeepClosed(
}

func (t *tbtc) shouldMonitorDeposit(depositAddress string) bool {
keepAddress, err := t.chain.KeepAddress(depositAddress)
t.monitoredDepositsCache.Sweep()
t.notMonitoredDepositsCache.Sweep()

if t.monitoredDepositsCache.Has(depositAddress) {
return true
}

if t.notMonitoredDepositsCache.Has(depositAddress) {
return false
}

signerIndex, err := t.getSignerIndex(depositAddress)
if err != nil {
logger.Errorf(
"could not check if deposit [%v] should be monitored: "+
"failed to get signer index: [%v]",
depositAddress,
err,
)
return false // return false but don't cache the result in case of error
}

if signerIndex < 0 {
t.notMonitoredDepositsCache.Add(depositAddress)
return false
}

t.monitoredDepositsCache.Add(depositAddress)
return true
}

func (t *tbtc) getSignerIndex(depositAddress string) (int, error) {
keepAddress, err := t.chain.KeepAddress(depositAddress)
if err != nil {
return -1, err
}

members, err := t.chain.GetMembers(common.HexToAddress(keepAddress))
if err != nil {
return false
return -1, err
}

for _, member := range members {
for index, member := range members {
if member == t.chain.Address() {
return true
return index, nil
}
}

return false
return -1, nil
}

func (t *tbtc) getSignerActionDelay(
depositAddress string,
) (time.Duration, error) {
signerIndex, err := t.getSignerIndex(depositAddress)
if err != nil {
return 0, err
}

return time.Duration(signerIndex) * t.signerActionDelayStep, nil
}

func (t *tbtc) waitDepositStateChangeConfirmation(
Expand Down
Loading

0 comments on commit b658b02

Please sign in to comment.