From c40169c6dffc479a11b0d1e394e5fafcb7312304 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 6 Sep 2023 08:08:40 -0400 Subject: [PATCH 01/15] fix/gh-actions-setup-postgres: fixing script to be resilient to array or object docker compose output (#10512) --- .../setup-postgres/wait-for-healthy-postgres.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup-postgres/wait-for-healthy-postgres.sh b/.github/actions/setup-postgres/wait-for-healthy-postgres.sh index 3f0efd66f3b..438cfbaff3d 100755 --- a/.github/actions/setup-postgres/wait-for-healthy-postgres.sh +++ b/.github/actions/setup-postgres/wait-for-healthy-postgres.sh @@ -2,10 +2,24 @@ RETRIES=10 until [ $RETRIES -eq 0 ]; do - if docker compose ps postgres --status running --format json | jq >/dev/null -e 'if (.[0].Health == "healthy") then true else false end'; then + DOCKER_OUTPUT=$(docker compose ps postgres --status running --format json) + JSON_TYPE=$(echo "$DOCKER_OUTPUT" | jq -r 'type') + + if [ "$JSON_TYPE" == "array" ]; then + HEALTH_STATUS=$(echo "$DOCKER_OUTPUT" | jq -r '.[0].Health') + elif [ "$JSON_TYPE" == "object" ]; then + HEALTH_STATUS=$(echo "$DOCKER_OUTPUT" | jq -r '.Health') + else + HEALTH_STATUS="Unknown JSON type: $JSON_TYPE" + fi + + echo "postgres health status: $HEALTH_STATUS" + if [ "$HEALTH_STATUS" == "healthy" ]; then exit 0 fi + echo "Waiting for postgres server, $((RETRIES--)) remaining attempts..." sleep 2 done + exit 1 From 19eb5fcd6c830b1ca38b636da4193eca52caa6b9 Mon Sep 17 00:00:00 2001 From: cfal Date: Wed, 6 Sep 2023 19:09:51 +0700 Subject: [PATCH 02/15] core: use loop.Keystore, support arbitrarily prefixed Cosmos addresses (#10416) * core: use loop.Keystore, support arbitrarily prefixed Cosmos addresses * Update core/chains/cosmos/cosmostxm/helpers_test.go Co-authored-by: Jordan Krage --------- Co-authored-by: Jordan Krage --- core/chains/cosmos/chain.go | 6 +- core/chains/cosmos/cosmostxm/helpers_test.go | 13 ++ core/chains/cosmos/cosmostxm/key_wrapper.go | 70 +++++----- .../cosmos/cosmostxm/keystore_adapter.go | 129 ++++++++++++++++++ core/chains/cosmos/cosmostxm/txm.go | 79 ++++++----- .../cosmos/cosmostxm/txm_internal_test.go | 48 ++++--- core/chains/cosmos/cosmostxm/txm_test.go | 14 +- core/services/chainlink/relayer_factory.go | 7 +- core/services/keystore/cosmos.go | 37 +++++ core/services/keystore/keys/cosmoskey/key.go | 5 +- 10 files changed, 305 insertions(+), 103 deletions(-) create mode 100644 core/chains/cosmos/cosmostxm/keystore_adapter.go diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index 91f5484e877..c73793c1c3a 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -20,13 +20,13 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/cosmostxm" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos/types" "github.com/smartcontractkit/chainlink/v2/core/chains/internal" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -54,7 +54,7 @@ type ChainOpts struct { QueryConfig pg.QConfig Logger logger.Logger DB *sqlx.DB - KeyStore keystore.Cosmos + KeyStore loop.Keystore EventBroadcaster pg.EventBroadcaster Configs types.Configs } @@ -112,7 +112,7 @@ type chain struct { lggr logger.Logger } -func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks keystore.Cosmos, logCfg pg.QConfig, eb pg.EventBroadcaster, cfgs types.Configs, lggr logger.Logger) (*chain, error) { +func newChain(id string, cfg *CosmosConfig, db *sqlx.DB, ks loop.Keystore, logCfg pg.QConfig, eb pg.EventBroadcaster, cfgs types.Configs, lggr logger.Logger) (*chain, error) { lggr = logger.With(lggr, "cosmosChainID", id) var ch = chain{ id: id, diff --git a/core/chains/cosmos/cosmostxm/helpers_test.go b/core/chains/cosmos/cosmostxm/helpers_test.go index 217160c3e80..ad93189082e 100644 --- a/core/chains/cosmos/cosmostxm/helpers_test.go +++ b/core/chains/cosmos/cosmostxm/helpers_test.go @@ -5,6 +5,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "golang.org/x/exp/maps" cosmosclient "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/client" ) @@ -28,3 +29,15 @@ func (txm *Txm) MarshalMsg(msg sdk.Msg) (string, []byte, error) { func (txm *Txm) SendMsgBatch(ctx context.Context) { txm.sendMsgBatch(ctx) } + +func (ka *KeystoreAdapter) Accounts(ctx context.Context) ([]string, error) { + ka.mutex.Lock() + defer ka.mutex.Unlock() + err := ka.updateMappingLocked() + if err != nil { + return nil, err + } + addresses := maps.Keys(ka.addressToPubKey) + + return addresses, nil +} diff --git a/core/chains/cosmos/cosmostxm/key_wrapper.go b/core/chains/cosmos/cosmostxm/key_wrapper.go index 6bc36f5aea7..1d2d686c8c0 100644 --- a/core/chains/cosmos/cosmostxm/key_wrapper.go +++ b/core/chains/cosmos/cosmostxm/key_wrapper.go @@ -1,56 +1,62 @@ package cosmostxm import ( - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "bytes" + "context" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) -var _ cryptotypes.PrivKey = KeyWrapper{} - -// KeyWrapper wrapper around a cosmos transmitter key -// for use in the cosmos txbuilder and client, see chainlink-cosmos. +// KeyWrapper uses a KeystoreAdapter to implement the cosmos-sdk PrivKey interface for a specific key. type KeyWrapper struct { - key cosmoskey.Key + adapter *KeystoreAdapter + account string } -// NewKeyWrapper create a key wrapper -func NewKeyWrapper(key cosmoskey.Key) KeyWrapper { - return KeyWrapper{key: key} +var _ cryptotypes.PrivKey = &KeyWrapper{} + +func NewKeyWrapper(adapter *KeystoreAdapter, account string) *KeyWrapper { + return &KeyWrapper{ + adapter: adapter, + account: account, + } } -// Reset nop -func (k KeyWrapper) Reset() {} +func (a *KeyWrapper) Bytes() []byte { + // don't expose the private key. + return nil +} -// ProtoMessage nop -func (k KeyWrapper) ProtoMessage() {} +func (a *KeyWrapper) Sign(msg []byte) ([]byte, error) { + return a.adapter.Sign(context.Background(), a.account, msg) +} -// String nop -func (k KeyWrapper) String() string { - return "" +func (a *KeyWrapper) PubKey() cryptotypes.PubKey { + pubKey, err := a.adapter.PubKey(a.account) + if err != nil { + // return an empty pubkey if it's not found. + return &secp256k1.PubKey{Key: []byte{}} + } + return pubKey } -// Bytes does not expose private key -func (k KeyWrapper) Bytes() []byte { - return []byte{} +func (a *KeyWrapper) Equals(other cryptotypes.LedgerPrivKey) bool { + return bytes.Equal(a.PubKey().Bytes(), other.PubKey().Bytes()) } -// Sign sign a message with key -func (k KeyWrapper) Sign(msg []byte) ([]byte, error) { - return k.key.ToPrivKey().Sign(msg) +func (a *KeyWrapper) Type() string { + return "secp256k1" } -// PubKey get the pubkey -func (k KeyWrapper) PubKey() cryptotypes.PubKey { - return k.key.PublicKey() +func (a *KeyWrapper) Reset() { + // no-op } -// Equals compare against another key -func (k KeyWrapper) Equals(a cryptotypes.LedgerPrivKey) bool { - return k.PubKey().Address().String() == a.PubKey().Address().String() +func (a *KeyWrapper) String() string { + return "" } -// Type nop -func (k KeyWrapper) Type() string { - return "" +func (a *KeyWrapper) ProtoMessage() { + // no-op } diff --git a/core/chains/cosmos/cosmostxm/keystore_adapter.go b/core/chains/cosmos/cosmostxm/keystore_adapter.go new file mode 100644 index 00000000000..c8556015c6e --- /dev/null +++ b/core/chains/cosmos/cosmostxm/keystore_adapter.go @@ -0,0 +1,129 @@ +package cosmostxm + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "sync" + + "github.com/cometbft/cometbft/crypto" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + "github.com/pkg/errors" + "golang.org/x/crypto/ripemd160" //nolint: staticcheck + + "github.com/smartcontractkit/chainlink-relay/pkg/loop" +) + +type accountInfo struct { + Account string + PubKey *secp256k1.PubKey +} + +// An adapter for a Cosmos loop.Keystore to translate public keys into bech32-prefixed account addresses. +type KeystoreAdapter struct { + keystore loop.Keystore + accountPrefix string + mutex sync.RWMutex + addressToPubKey map[string]*accountInfo +} + +func NewKeystoreAdapter(keystore loop.Keystore, accountPrefix string) *KeystoreAdapter { + return &KeystoreAdapter{ + keystore: keystore, + accountPrefix: accountPrefix, + addressToPubKey: make(map[string]*accountInfo), + } +} + +func (ka *KeystoreAdapter) updateMappingLocked() error { + accounts, err := ka.keystore.Accounts(context.Background()) + if err != nil { + return err + } + + // similar to cosmos-sdk, cache and re-use calculated bech32 addresses to prevent duplicated work. + // ref: https://github.com/cosmos/cosmos-sdk/blob/3b509c187e1643757f5ef8a0b5ae3decca0c7719/types/address.go#L705 + + type cacheEntry struct { + bech32Addr string + accountInfo *accountInfo + } + accountCache := make(map[string]cacheEntry, len(ka.addressToPubKey)) + for bech32Addr, accountInfo := range ka.addressToPubKey { + accountCache[accountInfo.Account] = cacheEntry{bech32Addr: bech32Addr, accountInfo: accountInfo} + } + + addressToPubKey := make(map[string]*accountInfo, len(accounts)) + for _, account := range accounts { + if prevEntry, ok := accountCache[account]; ok { + addressToPubKey[prevEntry.bech32Addr] = prevEntry.accountInfo + continue + } + pubKeyBytes, err := hex.DecodeString(account) + if err != nil { + return err + } + + if len(pubKeyBytes) != secp256k1.PubKeySize { + return errors.New("length of pubkey is incorrect") + } + + sha := sha256.Sum256(pubKeyBytes) + hasherRIPEMD160 := ripemd160.New() + _, _ = hasherRIPEMD160.Write(sha[:]) + address := crypto.Address(hasherRIPEMD160.Sum(nil)) + + bech32Addr, err := bech32.ConvertAndEncode(ka.accountPrefix, address) + if err != nil { + return err + } + + addressToPubKey[bech32Addr] = &accountInfo{ + Account: account, + PubKey: &secp256k1.PubKey{Key: pubKeyBytes}, + } + } + + ka.addressToPubKey = addressToPubKey + return nil +} + +func (ka *KeystoreAdapter) lookup(id string) (*accountInfo, error) { + ka.mutex.RLock() + ai, ok := ka.addressToPubKey[id] + ka.mutex.RUnlock() + if !ok { + // try updating the mapping once, incase there was an update on the keystore. + ka.mutex.Lock() + err := ka.updateMappingLocked() + if err != nil { + ka.mutex.Unlock() + return nil, err + } + ai, ok = ka.addressToPubKey[id] + ka.mutex.Unlock() + if !ok { + return nil, errors.New("No such id") + } + } + return ai, nil +} + +func (ka *KeystoreAdapter) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { + accountInfo, err := ka.lookup(id) + if err != nil { + return nil, err + } + return ka.keystore.Sign(ctx, accountInfo.Account, hash) +} + +// Returns the cosmos PubKey associated with the prefixed address. +func (ka *KeystoreAdapter) PubKey(address string) (cryptotypes.PubKey, error) { + accountInfo, err := ka.lookup(address) + if err != nil { + return nil, err + } + return accountInfo.PubKey, nil +} diff --git a/core/chains/cosmos/cosmostxm/txm.go b/core/chains/cosmos/cosmostxm/txm.go index 7b0e2ad2887..84118b9381b 100644 --- a/core/chains/cosmos/cosmostxm/txm.go +++ b/core/chains/cosmos/cosmostxm/txm.go @@ -25,10 +25,9 @@ import ( "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/db" "github.com/smartcontractkit/chainlink-relay/pkg/logger" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -40,32 +39,33 @@ var ( // Txm manages transactions for the cosmos blockchain. type Txm struct { - starter utils.StartStopOnce - eb pg.EventBroadcaster - sub pg.Subscription - orm *ORM - lggr logger.Logger - tc func() (cosmosclient.ReaderWriter, error) - ks keystore.Cosmos - stop, done chan struct{} - cfg coscfg.Config - gpe cosmosclient.ComposedGasPriceEstimator + starter utils.StartStopOnce + eb pg.EventBroadcaster + sub pg.Subscription + orm *ORM + lggr logger.Logger + tc func() (cosmosclient.ReaderWriter, error) + keystoreAdapter *KeystoreAdapter + stop, done chan struct{} + cfg coscfg.Config + gpe cosmosclient.ComposedGasPriceEstimator } // NewTxm creates a txm. Uses simulation so should only be used to send txes to trusted contracts i.e. OCR. -func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmosclient.ComposedGasPriceEstimator, chainID string, cfg coscfg.Config, ks keystore.Cosmos, lggr logger.Logger, logCfg pg.QConfig, eb pg.EventBroadcaster) *Txm { +func NewTxm(db *sqlx.DB, tc func() (cosmosclient.ReaderWriter, error), gpe cosmosclient.ComposedGasPriceEstimator, chainID string, cfg coscfg.Config, ks loop.Keystore, lggr logger.Logger, logCfg pg.QConfig, eb pg.EventBroadcaster) *Txm { lggr = logger.Named(lggr, "Txm") + keystoreAdapter := NewKeystoreAdapter(ks, cfg.Bech32Prefix()) return &Txm{ - starter: utils.StartStopOnce{}, - eb: eb, - orm: NewORM(chainID, db, lggr, logCfg), - ks: ks, - tc: tc, - lggr: lggr, - stop: make(chan struct{}), - done: make(chan struct{}), - cfg: cfg, - gpe: gpe, + starter: utils.StartStopOnce{}, + eb: eb, + orm: NewORM(chainID, db, lggr, logCfg), + lggr: lggr, + tc: tc, + keystoreAdapter: keystoreAdapter, + stop: make(chan struct{}), + done: make(chan struct{}), + cfg: cfg, + gpe: gpe, } } @@ -259,14 +259,11 @@ func (txm *Txm) sendMsgBatch(ctx context.Context) { } for s, msgs := range msgsByFrom { sender, _ := sdk.AccAddressFromBech32(s) // Already checked validity above - key, err := txm.ks.Get(sender.String()) + err := txm.sendMsgBatchFromAddress(ctx, gasPrice, sender, msgs) if err != nil { - txm.lggr.Errorw("unable to find key for from address", "err", err, "from", sender.String()) - // We check the transmitter key exists when the job is added. So it would have to be deleted - // after it was added for this to happen. Retry on next poll should the key be re-added. + txm.lggr.Errorw("Could not send message batch", "err", err, "from", sender.String()) continue } - txm.sendMsgBatchFromAddress(ctx, gasPrice, sender, key, msgs) if ctx.Err() != nil { return } @@ -274,18 +271,18 @@ func (txm *Txm) sendMsgBatch(ctx context.Context) { } -func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoin, sender sdk.AccAddress, key cosmoskey.Key, msgs adapters.Msgs) { +func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoin, sender sdk.AccAddress, msgs adapters.Msgs) error { tc, err := txm.tc() if err != nil { logger.Criticalw(txm.lggr, "unable to get client", "err", err) - return + return err } an, sn, err := tc.Account(sender) if err != nil { txm.lggr.Warnw("unable to read account", "err", err, "from", sender.String()) // If we can't read the account, assume transient api issues and leave msgs unstarted // to retry on next poll. - return + return err } txm.lggr.Debugw("simulating batch", "from", sender, "msgs", msgs, "seqnum", sn) @@ -296,27 +293,27 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi // Note one rare scenario in which this can happen: the cosmos node misbehaves // in that it confirms a txhash is present but still gives an old seq num. // This is benign as the next retry will succeeds. - return + return err } txm.lggr.Debugw("simulation results", "from", sender, "succeeded", simResults.Succeeded, "failed", simResults.Failed) err = txm.orm.UpdateMsgs(simResults.Failed.GetSimMsgsIDs(), db.Errored, nil) if err != nil { txm.lggr.Errorw("unable to mark failed sim txes as errored", "err", err, "from", sender.String()) // If we can't mark them as failed retry on next poll. Presumably same ones will fail. - return + return err } // Continue if there are no successful txes if len(simResults.Succeeded) == 0 { txm.lggr.Warnw("all sim msgs errored, not sending tx", "from", sender.String()) - return + return errors.New("all sim msgs errored") } // Get the gas limit for the successful batch s, err := tc.SimulateUnsigned(simResults.Succeeded.GetMsgs(), sn) if err != nil { // In the OCR context this should only happen upon stale report txm.lggr.Warnw("unexpected failure after successful simulation", "err", err) - return + return err } gasLimit := s.GasInfo.GasUsed @@ -324,14 +321,14 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi if err != nil { txm.lggr.Warnw("unable to get latest block", "err", err, "from", sender.String()) // Assume transient api issue and retry. - return + return err } timeoutHeight := uint64(lb.Block.Header.Height) + uint64(txm.cfg.BlocksUntilTxTimeout()) signedTx, err := tc.CreateAndSign(simResults.Succeeded.GetMsgs(), an, sn, gasLimit, txm.cfg.GasLimitMultiplier(), - gasPrice, NewKeyWrapper(key), timeoutHeight) + gasPrice, NewKeyWrapper(txm.keystoreAdapter, sender.String()), timeoutHeight) if err != nil { txm.lggr.Errorw("unable to sign tx", "err", err, "from", sender.String()) - return + return err } // We need to ensure that we either broadcast successfully and mark the tx as @@ -367,14 +364,16 @@ func (txm *Txm) sendMsgBatchFromAddress(ctx context.Context, gasPrice sdk.DecCoi if err != nil { txm.lggr.Errorw("error broadcasting tx", "err", err, "from", sender.String()) // Was unable to broadcast, retry on next poll - return + return err } maxPolls, pollPeriod := txm.confirmPollConfig() if err := txm.confirmTx(ctx, tc, resp.TxResponse.TxHash, simResults.Succeeded.GetSimMsgsIDs(), maxPolls, pollPeriod); err != nil { txm.lggr.Errorw("error confirming tx", "err", err, "hash", resp.TxResponse.TxHash) - return + return err } + + return nil } func (txm *Txm) confirmPollConfig() (maxPolls int, pollPeriod time.Duration) { diff --git a/core/chains/cosmos/cosmostxm/txm_internal_test.go b/core/chains/cosmos/cosmostxm/txm_internal_test.go index 6a9944a1a53..17eeb74421a 100644 --- a/core/chains/cosmos/cosmostxm/txm_internal_test.go +++ b/core/chains/cosmos/cosmostxm/txm_internal_test.go @@ -54,22 +54,27 @@ func TestTxm(t *testing.T) { lggr := testutils.LoggerAssertMaxLevel(t, zapcore.ErrorLevel) ks := keystore.New(db, utils.FastScryptParams, lggr, pgtest.NewQConfig(true)) require.NoError(t, ks.Unlock("blah")) - k1, err := ks.Cosmos().Create() - require.NoError(t, err) - sender1, err := cosmostypes.AccAddressFromBech32(k1.PublicKeyStr()) - require.NoError(t, err) - k2, err := ks.Cosmos().Create() - require.NoError(t, err) - sender2, err := cosmostypes.AccAddressFromBech32(k2.PublicKeyStr()) + + for i := 0; i < 4; i++ { + _, err := ks.Cosmos().Create() + require.NoError(t, err) + } + + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + adapter := cosmostxm.NewKeystoreAdapter(loopKs, "wasm") + accounts, err := adapter.Accounts(testutils.Context(t)) require.NoError(t, err) - k3, err := ks.Cosmos().Create() + require.Equal(t, len(accounts), 4) + + sender1, err := cosmostypes.AccAddressFromBech32(accounts[0]) require.NoError(t, err) - contract, err := cosmostypes.AccAddressFromBech32(k3.PublicKeyStr()) + sender2, err := cosmostypes.AccAddressFromBech32(accounts[1]) require.NoError(t, err) - k4, err := ks.Cosmos().Create() + contract, err := cosmostypes.AccAddressFromBech32(accounts[2]) require.NoError(t, err) - contract2, err := cosmostypes.AccAddressFromBech32(k4.PublicKeyStr()) + contract2, err := cosmostypes.AccAddressFromBech32(accounts[3]) require.NoError(t, err) + logCfg := pgtest.NewQConfig(true) chainID := cosmostest.RandomChainID() two := int64(2) @@ -90,7 +95,8 @@ func TestTxm(t *testing.T) { t.Run("single msg", func(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, ks.Cosmos(), lggr, logCfg, nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, logCfg, nil) // Enqueue a single msg, then send it in a batch id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`1`), sender1, contract)) @@ -126,7 +132,8 @@ func TestTxm(t *testing.T) { t.Run("two msgs different accounts", func(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`0`), sender1, contract)) require.NoError(t, err) @@ -181,7 +188,8 @@ func TestTxm(t *testing.T) { t.Run("two msgs different contracts", func(t *testing.T) { tc := newReaderWriterMock(t) tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) id1, err := txm.Enqueue(contract.String(), generateExecuteMsg(t, []byte(`0`), sender1, contract)) require.NoError(t, err) @@ -244,7 +252,8 @@ func TestTxm(t *testing.T) { TxResponse: &cosmostypes.TxResponse{TxHash: "0x123"}, }, errors.New("not found")).Twice() tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) i, err := txm.ORM().InsertMsg("blah", "", []byte{0x01}) require.NoError(t, err) txh := "0x123" @@ -274,7 +283,8 @@ func TestTxm(t *testing.T) { TxResponse: &cosmostypes.TxResponse{TxHash: txHash3}, }, nil).Once() tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfg, loopKs, lggr, pgtest.NewQConfig(true), nil) // Insert and broadcast 3 msgs with different txhashes. id1, err := txm.ORM().InsertMsg("blah", "", []byte{0x01}) @@ -317,7 +327,8 @@ func TestTxm(t *testing.T) { TxMsgTimeout: &timeout, }} cfgShortExpiry.SetDefaults() - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgShortExpiry, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgShortExpiry, loopKs, lggr, pgtest.NewQConfig(true), nil) // Send a single one expired id1, err := txm.ORM().InsertMsg("blah", "", []byte{0x03}) @@ -362,7 +373,8 @@ func TestTxm(t *testing.T) { MaxMsgsPerBatch: &two, }} cfgMaxMsgs.SetDefaults() - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgMaxMsgs, ks.Cosmos(), lggr, pgtest.NewQConfig(true), nil) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, cfgMaxMsgs, loopKs, lggr, pgtest.NewQConfig(true), nil) // Leftover started is processed msg1 := generateExecuteMsg(t, []byte{0x03}, sender1, contract) diff --git a/core/chains/cosmos/cosmostxm/txm_test.go b/core/chains/cosmos/cosmostxm/txm_test.go index 7bfd76e1d8c..9966ff44a5b 100644 --- a/core/chains/cosmos/cosmostxm/txm_test.go +++ b/core/chains/cosmos/cosmostxm/txm_test.go @@ -63,11 +63,17 @@ func TestTxm_Integration(t *testing.T) { tc, err := cosmosclient.NewClient(chainID, tendermintURL, cosmos.DefaultRequestTimeout, lggr) require.NoError(t, err) + loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks.Cosmos()} + keystoreAdapter := cosmostxm.NewKeystoreAdapter(loopKs, *cosmosChain.Bech32Prefix) + // First create a transmitter key and fund it with 1k native tokens require.NoError(t, ks.Unlock("blah")) - transmitterKey, err := ks.Cosmos().Create() + err = ks.Cosmos().EnsureKey() + require.NoError(t, err) + ksAccounts, err := keystoreAdapter.Accounts(testutils.Context(t)) require.NoError(t, err) - transmitterID, err := sdk.AccAddressFromBech32(transmitterKey.PublicKeyStr()) + transmitterAddress := ksAccounts[0] + transmitterID, err := sdk.AccAddressFromBech32(transmitterAddress) require.NoError(t, err) an, sn, err := tc.Account(accounts[0].Address) require.NoError(t, err) @@ -82,13 +88,13 @@ func TestTxm_Integration(t *testing.T) { // the chainlink-cosmos repo instead of copying it to cores testdata contractID := cosmosclient.DeployTestContract(t, tendermintURL, chainID, *cosmosChain.FeeToken, accounts[0], cosmosclient.Account{ Name: "transmitter", - PrivateKey: cosmostxm.NewKeyWrapper(transmitterKey), + PrivateKey: cosmostxm.NewKeyWrapper(keystoreAdapter, transmitterAddress), Address: transmitterID, }, tc, testdir, "../../../testdata/cosmos/my_first_contract.wasm") tcFn := func() (cosmosclient.ReaderWriter, error) { return tc, nil } // Start txm - txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, &chainConfig, ks.Cosmos(), lggr, pgtest.NewQConfig(true), eb) + txm := cosmostxm.NewTxm(db, tcFn, *gpe, chainID, &chainConfig, loopKs, lggr, pgtest.NewQConfig(true), eb) require.NoError(t, txm.Start(testutils.Context(t))) // Change the contract state diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 6321b575b13..94d0e43403a 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -227,7 +227,10 @@ type CosmosFactoryConfig struct { func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConfig) (map[relay.ID]cosmos.LoopRelayerChainer, error) { relayers := make(map[relay.ID]cosmos.LoopRelayerChainer) - var lggr = r.Logger.Named("Cosmos") + var ( + lggr = r.Logger.Named("Cosmos") + loopKs = &keystore.CosmosLoopKeystore{Cosmos: config.Keystore} + ) // create one relayer per chain id for _, chainCfg := range config.CosmosConfigs { @@ -237,7 +240,7 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf QueryConfig: r.QConfig, Logger: lggr.Named(relayId.ChainID.String()), DB: r.DB, - KeyStore: config.Keystore, + KeyStore: loopKs, EventBroadcaster: config.EventBroadcaster, } opts.Configs = cosmos.NewConfigs(cosmos.CosmosConfigs{chainCfg}) diff --git a/core/services/keystore/cosmos.go b/core/services/keystore/cosmos.go index 07abafa3efd..c06dfcdbcea 100644 --- a/core/services/keystore/cosmos.go +++ b/core/services/keystore/cosmos.go @@ -1,10 +1,12 @@ package keystore import ( + "context" "fmt" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" ) @@ -144,3 +146,38 @@ func (ks *cosmos) getByID(id string) (cosmoskey.Key, error) { } return key, nil } + +// CosmosLoopKeystore implements the [github.com/smartcontractkit/chainlink-relay/pkg/loop.Keystore] interface and +// handles signing for Cosmos messages. +type CosmosLoopKeystore struct { + Cosmos +} + +var _ loop.Keystore = &CosmosLoopKeystore{} + +func (lk *CosmosLoopKeystore) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { + k, err := lk.Get(id) + if err != nil { + return nil, err + } + // loopp spec requires passing nil hash to check existence of id + if hash == nil { + return nil, nil + } + + return k.ToPrivKey().Sign(hash) +} + +func (lk *CosmosLoopKeystore) Accounts(ctx context.Context) ([]string, error) { + keys, err := lk.GetAll() + if err != nil { + return nil, err + } + + accounts := []string{} + for _, k := range keys { + accounts = append(accounts, k.PublicKeyStr()) + } + + return accounts, nil +} diff --git a/core/services/keystore/keys/cosmoskey/key.go b/core/services/keystore/keys/cosmoskey/key.go index 6783232e8b7..3e516a21ab5 100644 --- a/core/services/keystore/keys/cosmoskey/key.go +++ b/core/services/keystore/keys/cosmoskey/key.go @@ -12,7 +12,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/types" ) var secpSigningAlgo, _ = keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), []keyring.SignatureAlgo{hd.Secp256k1}) @@ -78,10 +77,8 @@ func (key Key) PublicKey() (pubKey cryptotypes.PubKey) { return key.k.PubKey() } -// PublicKeyStr returns the cosmos address of the public key func (key Key) PublicKeyStr() string { - addr := types.AccAddress(key.k.PubKey().Address()) - return addr.String() + return fmt.Sprintf("%X", key.k.PubKey().Bytes()) } func (key Key) Raw() Raw { From 43030bdc6fa314c47f02b076e3f32d408f6eeb9e Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 6 Sep 2023 07:10:04 -0500 Subject: [PATCH 03/15] shadow: declaration of err shadows declaration at line * (govet) (#10468) --- core/chains/evm/chain.go | 9 +-- core/chains/evm/chain_test.go | 11 +-- core/chains/evm/log/helpers_test.go | 3 +- core/chains/evm/txmgr/broadcaster_test.go | 68 +++++++------------ core/internal/cltest/job_factories.go | 4 +- core/internal/cltest/mocks.go | 8 +-- core/internal/features/features_test.go | 3 +- core/services/blockhashstore/bhs_test.go | 3 +- core/services/blockhashstore/delegate_test.go | 3 +- .../chainlink/relayer_chain_interoperators.go | 7 +- core/services/chainlink/relayer_factory.go | 5 +- core/services/cron/cron_test.go | 6 +- core/services/directrequest/delegate_test.go | 9 +-- core/services/feeds/orm_test.go | 3 +- core/services/feeds/service_test.go | 3 +- core/services/fluxmonitorv2/orm_test.go | 6 +- core/services/functions/listener_test.go | 6 +- core/services/job/helpers_test.go | 5 +- core/services/job/job_orm_test.go | 60 ++++++---------- .../job/job_pipeline_orm_integration_test.go | 9 +-- core/services/job/runner_integration_test.go | 29 ++++---- core/services/job/spawner_test.go | 8 +-- .../registry_synchronizer_helper_test.go | 3 +- core/services/keeper/upkeep_executer_test.go | 6 +- core/services/ocr2/delegate.go | 2 +- core/services/ocr2/delegate_test.go | 3 +- .../v1/internal/testutils.go | 16 ++--- core/services/pipeline/orm_test.go | 10 ++- core/services/pipeline/runner_test.go | 6 +- core/services/pipeline/task.eth_call_test.go | 4 +- core/services/pipeline/task.eth_tx_test.go | 3 +- core/services/relay/evm/relayer_extender.go | 10 +-- core/services/vrf/delegate_test.go | 3 +- core/web/resolver/eth_key_test.go | 4 +- 34 files changed, 123 insertions(+), 215 deletions(-) diff --git a/core/chains/evm/chain.go b/core/chains/evm/chain.go index f63983a3d5c..524e84fd51b 100644 --- a/core/chains/evm/chain.go +++ b/core/chains/evm/chain.go @@ -96,14 +96,11 @@ type LegacyChainContainer interface { var _ LegacyChainContainer = &LegacyChains{} -func NewLegacyChains(cfg AppConfig, m map[string]Chain) (*LegacyChains, error) { - if cfg == nil { - return nil, fmt.Errorf("must provide non-nil app config") - } +func NewLegacyChains(m map[string]Chain, evmCfgs toml.EVMConfigs) *LegacyChains { return &LegacyChains{ ChainsKV: chains.NewChainsKV[Chain](m), - cfgs: chains.NewConfigs[utils.Big, evmtypes.Node](cfg.EVMConfigs()), - }, nil + cfgs: chains.NewConfigs[utils.Big, evmtypes.Node](evmCfgs), + } } func (c *LegacyChains) ChainNodeConfigs() evmtypes.Configs { diff --git a/core/chains/evm/chain_test.go b/core/chains/evm/chain_test.go index e80bfc02934..3ae8a74bfe2 100644 --- a/core/chains/evm/chain_test.go +++ b/core/chains/evm/chain_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/mocks" @@ -20,16 +21,16 @@ func TestLegacyChains(t *testing.T) { c.On("ID").Return(big.NewInt(7)) m := map[string]evm.Chain{c.ID().String(): c} - l, err := evm.NewLegacyChains(evmCfg, m) - assert.NoError(t, err) + l := evm.NewLegacyChains(m, evmCfg.EVMConfigs()) assert.NotNil(t, l.ChainNodeConfigs()) got, err := l.Get(c.ID().String()) assert.NoError(t, err) assert.Equal(t, c, got) - l, err = evm.NewLegacyChains(nil, m) - assert.Error(t, err) - assert.Nil(t, l) + require.NotPanics(t, func() { + l = evm.NewLegacyChains(m, nil) + assert.NotNil(t, l.ChainNodeConfigs()) + }) } func TestRelayConfigInit(t *testing.T) { diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index e11c9faaf46..d55a44373f2 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -121,8 +121,7 @@ func (c broadcasterHelperCfg) newWithEthClient(t *testing.T, ethClient evmclient LogBroadcaster: &log.NullBroadcaster{}, MailMon: mailMon, }) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) pipelineHelper := cltest.NewJobPipelineV2(t, config.WebServer(), config.JobPipeline(), config.Database(), legacyChains, c.db, kst, nil, nil) return &broadcasterHelper{ diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 2e3a1e0f731..2e665bc3c8f 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -58,24 +58,25 @@ func NewTestEthBroadcaster( config evmconfig.ChainScopedConfig, checkerFactory txmgr.TransmitCheckerFactory, nonceAutoSync bool, -) (*txmgr.Broadcaster, error) { +) *txmgr.Broadcaster { t.Helper() - eventBroadcaster := cltest.NewEventBroadcaster(t, config.Database().URL()) - err := eventBroadcaster.Start(testutils.Context(t.(*testing.T))) - require.NoError(t, err) - t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) + eb := cltest.NewEventBroadcaster(t, config.Database().URL()) + ctx := testutils.Context(t) + require.NoError(t, eb.Start(ctx)) + t.Cleanup(func() { assert.NoError(t, eb.Close()) }) + lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees()) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, keyStore) - ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) + ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eb, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() - err = ethBroadcaster.Start(testutils.Context(t)) + require.NoError(t, ethBroadcaster.Start(ctx)) t.Cleanup(func() { assert.NoError(t, ethBroadcaster.Close()) }) - return ethBroadcaster, err + return ethBroadcaster } func TestEthBroadcaster_Lifecycle(t *testing.T) { @@ -150,8 +151,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") timeNow := time.Now() @@ -351,8 +351,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(rnd + 2) }) evmcfg = evmtest.NewChainScopedConfig(t, cfg) - eb, err = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) - require.NoError(t, err) + eb = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) t.Run("sends transactions with type 0x2 in EIP-1559 mode", func(t *testing.T) { ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -500,8 +499,7 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) checkerFactory := &testCheckerFactory{} - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, checkerFactory, false) checker := txmgr.TransmitCheckerSpec{ CheckerType: txmgr.TransmitCheckerTypeSimulate, @@ -648,8 +646,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { assert.Equal(t, int(1600), int(tx.Gas())) @@ -729,8 +726,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so evm_key_states.next_nonce has not been @@ -768,8 +764,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so keys.next_nonce has not been @@ -807,8 +802,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so keys.next_nonce has not been @@ -845,8 +839,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so keys.next_nonce has not been @@ -885,8 +878,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so keys.next_nonce has not been @@ -929,8 +921,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) // Crashed right after we commit the database transaction that saved // the nonce to the eth_tx so keys.next_nonce has not been @@ -996,8 +987,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) @@ -1474,8 +1464,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - eb2, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - require.NoError(t, err) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) // First was underpriced @@ -1565,8 +1554,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - eb2, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - require.NoError(t, err) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" localNextNonce := getLocalNextNonce(t, ethKeyStore, fromAddress) @@ -1596,8 +1584,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) })) - eb2, err := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - require.NoError(t, err) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(testutils.Context(t), fromAddress) require.Error(t, err) @@ -1610,8 +1597,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault })) - eb2, err = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) - require.NoError(t, err) + eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1659,8 +1645,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { next, err := realKeystore.Eth().NextSequence(fromAddress, testutils.FixtureChainID) require.NoError(t, err) kst.On("NextSequence", fromAddress, testutils.FixtureChainID, mock.Anything).Return(next, nil).Once() - eb, err := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, ethClient, kst, evmcfg, &testCheckerFactory{}, false) t.Run("tx signing fails", func(t *testing.T) { etx := cltest.MustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1734,8 +1719,7 @@ func TestEthBroadcaster_Trigger(t *testing.T) { txStore := cltest.NewTestTxStore(t, db, cfg.Database()) evmcfg := evmtest.NewChainScopedConfig(t, cfg) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - eb, err := NewTestEthBroadcaster(t, txStore, evmtest.NewEthClientMockWithDefaultChain(t), ethKeyStore, evmcfg, &testCheckerFactory{}, false) - require.NoError(t, err) + eb := NewTestEthBroadcaster(t, txStore, evmtest.NewEthClientMockWithDefaultChain(t), ethKeyStore, evmcfg, &testCheckerFactory{}, false) eb.Trigger(testutils.NewAddress()) eb.Trigger(testutils.NewAddress()) diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index fd496c5f972..ef59a9d312c 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -6,7 +6,6 @@ import ( "github.com/google/uuid" "github.com/smartcontractkit/sqlx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -66,8 +65,7 @@ func getORMs(t *testing.T, db *sqlx.DB) (jobORM job.ORM, pipelineORM pipeline.OR pipelineORM = pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgeORM := bridges.NewORM(db, lggr, config.Database()) cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - assert.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) jobORM = job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) t.Cleanup(func() { jobORM.Close() }) return diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 4984b8157f1..423791f716c 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -27,7 +27,6 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/robfig/cron/v3" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) // MockSubscription a mock subscription @@ -424,14 +423,13 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg ch.On("ID").Return(scopedCfg.EVM().ChainID()) ch.On("Config").Return(scopedCfg) - return NewLegacyChainsWithChain(t, ch, cfg) + return NewLegacyChainsWithChain(ch, cfg) } -func NewLegacyChainsWithChain(t testing.TB, ch evm.Chain, cfg evm.AppConfig) evm.LegacyChainContainer { +func NewLegacyChainsWithChain(ch evm.Chain, cfg evm.AppConfig) evm.LegacyChainContainer { m := map[string]evm.Chain{ch.ID().String(): ch} - legacyChains, err := evm.NewLegacyChains(cfg, m) - require.NoError(t, err) + legacyChains := evm.NewLegacyChains(m, cfg.EVMConfigs()) legacyChains.SetDefault(ch) return legacyChains } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index e730ec5f3a0..2e2d29c248d 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -1380,8 +1380,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { ethClient.On("HeadByHash", mock.Anything, h41.Hash).Return(&h41, nil).Maybe() ethClient.On("HeadByHash", mock.Anything, h42.Hash).Return(&h42, nil).Maybe() - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) for _, re := range cc.Slice() { require.NoError(t, re.Start(testutils.Context(t))) } diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index d0e5ac71a7b..79494ea41f6 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -30,8 +30,7 @@ func TestStoreRotatesFromAddresses(t *testing.T) { kst := cltest.NewKeyStore(t, db, cfg.Database()) require.NoError(t, kst.Unlock(cltest.Password)) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, KeyStore: kst.Eth(), GeneralConfig: cfg, Client: ethClient}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) chain, err := legacyChains.Get(cltest.FixtureChainID.String()) require.NoError(t, err) lggr := logger.TestLogger(t) diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 3a9c01ae399..78242d519d7 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -70,8 +70,7 @@ func createTestDelegate(t *testing.T) (*blockhashstore.Delegate, *testData) { LogPoller: lp, }, ) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) return blockhashstore.NewDelegate(lggr, legacyChains, kst), &testData{ ethClient: ethClient, ethKeyStore: kst, diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 01c46c691ff..65859338b6c 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -9,6 +9,7 @@ import ( "github.com/smartcontractkit/chainlink-relay/pkg/loop" "github.com/smartcontractkit/chainlink-relay/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/cosmos" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -117,11 +118,7 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi } } - legacy, err := evm.NewLegacyChains(config.AppConfig, legacyMap) - if err != nil { - return err - } - op.legacyChains.EVMChains = legacy + op.legacyChains.EVMChains = evm.NewLegacyChains(legacyMap, config.AppConfig.EVMConfigs()) // TODO BCF-2510 this may not be necessary if EVM is not enabled by default if defaultChain != nil { op.legacyChains.EVMChains.SetDefault(defaultChain) diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 94d0e43403a..4ff70a585ac 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -55,10 +55,7 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m if err != nil { return nil, err } - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) - if err != nil { - return nil, err - } + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(evmRelayExtenders) for _, ext := range evmRelayExtenders.Slice() { relayID := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(ext.Chain().ID().String())} chain, err := legacyChains.Get(relayID.ChainID.String()) diff --git a/core/services/cron/cron_test.go b/core/services/cron/cron_test.go index 1d89248d4a5..174f80586ae 100644 --- a/core/services/cron/cron_test.go +++ b/core/services/cron/cron_test.go @@ -32,8 +32,7 @@ func TestCronV2Pipeline(t *testing.T) { lggr := logger.TestLogger(t) orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayerExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayerExtenders) jobORM := job.NewORM(db, legacyChains, orm, btORM, keyStore, lggr, cfg.Database()) jb := &job.Job{ @@ -45,8 +44,7 @@ func TestCronV2Pipeline(t *testing.T) { } delegate := cron.NewDelegate(runner, lggr) - err = jobORM.CreateJob(jb) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(jb)) serviceArray, err := delegate.ServicesForSpec(*jb) require.NoError(t, err) assert.Len(t, serviceArray, 1) diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 8a453dbe9db..0a4334e8693 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -47,8 +47,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, MailMon: mailMon, KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayerExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayerExtenders) delegate := directrequest.NewDelegate(lggr, runner, nil, legacyChains, mailMon) t.Run("Spec without DirectRequestSpec", func(t *testing.T) { @@ -89,8 +88,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi lggr := logger.TestLogger(t) orm := pipeline.NewORM(db, lggr, cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, lggr, cfg.Database()) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := job.NewORM(db, legacyChains, orm, btORM, keyStore, lggr, cfg.Database()) delegate := directrequest.NewDelegate(lggr, runner, orm, legacyChains, mailMon) @@ -99,8 +97,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi if specF != nil { specF(jb) } - err = jobORM.CreateJob(jb) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(jb)) serviceArray, err := delegate.ServicesForSpec(*jb) require.NoError(t, err) assert.Len(t, serviceArray, 1) diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 5294028b352..f2dacc4f02f 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -1479,8 +1479,7 @@ func createJob(t *testing.T, db *sqlx.DB, externalJobID uuid.UUID) *job.Job { bridgeORM = bridges.NewORM(db, lggr, config.Database()) relayExtenders = evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) ) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, config.Database()) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) require.NoError(t, keyStore.P2P().Add(cltest.DefaultP2PKey)) diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index a2d57338c5c..c864b8c1922 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -181,8 +181,7 @@ func setupTestServiceCfg(t *testing.T, overrideCfg func(c *chainlink.Config, s * ethKeyStore := cltest.NewKeyStore(t, db, gcfg.Database()).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{GeneralConfig: gcfg, HeadTracker: headtracker.NullTracker, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) keyStore.On("Eth").Return(ethKeyStore) keyStore.On("CSA").Return(csaKeystore) keyStore.On("P2P").Return(p2pKeystore) diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index e7185efa7bd..caaea838517 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -95,8 +95,7 @@ func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { bridgeORM := bridges.NewORM(db, lggr, cfg.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{GeneralConfig: cfg, DB: db, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) // Instantiate a real job ORM because we need to create a job to satisfy // a check in pipeline.CreateRun jobORM := job.NewORM(db, legacyChains, pipelineORM, bridgeORM, keyStore, lggr, cfg.Database()) @@ -106,8 +105,7 @@ func TestORM_UpdateFluxMonitorRoundStats(t *testing.T) { var roundID uint32 = 1 jb := makeJob(t) - err = jobORM.CreateJob(jb) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(jb)) for expectedCount := uint64(1); expectedCount < 4; expectedCount++ { f := time.Now() diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 0c74b0563f4..a06fcf3e3b2 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -90,8 +90,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, KeyStore: kst.Eth(), LogBroadcaster: broadcaster, MailMon: mailMon}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) chain := legacyChains.Slice()[0] lggr := logger.TestLogger(t) @@ -127,8 +126,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe decryptor := threshold_mocks.NewDecryptor(t) var pluginConfig config.PluginConfig - err = json.Unmarshal(jsonConfig.Bytes(), &pluginConfig) - require.NoError(t, err) + require.NoError(t, json.Unmarshal(jsonConfig.Bytes(), &pluginConfig)) contractAddress := "0xa" diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 106ba8d27c7..21f3a8daa99 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -220,9 +220,8 @@ func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralC s := fmt.Sprintf(minimalNonBootstrapTemplate, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout) keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: evmtest.NewEthClientMockWithDefaultChain(t), GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) - _, err = ocr.ValidatedOracleSpecToml(legacyChains, s) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + _, err := ocr.ValidatedOracleSpecToml(legacyChains, s) require.NoError(t, err) err = toml.Unmarshal([]byte(s), &os) require.NoError(t, err) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index de2ee44c2ce..1f5dba452fe 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -83,8 +83,7 @@ func TestORM(t *testing.T) { bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) borm := bridges.NewORM(db, logger.TestLogger(t), config.Database()) @@ -317,8 +316,7 @@ func TestORM_DeleteJob_DeletesAssociatedRecords(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) scopedConfig := evmtest.NewChainScopedConfig(t, config) korm := keeper.NewORM(db, logger.TestLogger(t), scopedConfig.Database()) @@ -418,8 +416,7 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) @@ -502,8 +499,7 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) cc := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) fromAddresses := []string{cltest.NewEIP55Address().String(), cltest.NewEIP55Address().String()} @@ -588,8 +584,7 @@ func TestORM_CreateJob_OCRBootstrap(t *testing.T) { pipelineORM := pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := ocrbootstrap.ValidatedBootstrapSpecToml(testspecs.OCRBootstrapSpec) @@ -629,8 +624,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) defaultChainID := config.DefaultChainID() @@ -764,8 +758,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -829,8 +822,7 @@ func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) require.True(t, relayExtenders.Len() > 0) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jobORM := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := ocr2validate.ValidatedOracleSpecToml(config.OCR2(), config.Insecure(), testspecs.OCR2EVMSpecMinimal) @@ -942,8 +934,7 @@ func Test_FindJobs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1024,8 +1015,7 @@ func Test_FindJob(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1242,8 +1232,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) @@ -1284,9 +1273,8 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { }) }) relayExtenders2 := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: newCfg, KeyStore: keyStore.Eth()}) - legacyChains2, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders2) + legacyChains2 := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders2) - require.NoError(t, err) orm2 := NewTestORM(t, db, legacyChains2, pipelineORM, bridgesORM, keyStore, config.Database()) jbs, err := orm2.FindJobsByPipelineSpecIDs([]int32{jb.PipelineSpecID}) @@ -1307,8 +1295,7 @@ func Test_FindPipelineRuns(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1369,8 +1356,7 @@ func Test_PipelineRunsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1431,8 +1417,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, address := cltest.MustInsertRandomKey(t, keyStore.Eth()) @@ -1540,8 +1525,7 @@ func Test_FindPipelineRunsByIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) @@ -1599,8 +1583,7 @@ func Test_FindPipelineRunByID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) @@ -1645,8 +1628,7 @@ func Test_FindJobWithoutSpecErrors(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) @@ -1685,8 +1667,7 @@ func Test_FindSpecErrorsByJobIDs(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.DirectRequestSpec) @@ -1722,8 +1703,7 @@ func Test_CountPipelineRunsByJobID(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) bridgesORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := NewTestORM(t, db, legacyChains, pipelineORM, bridgesORM, keyStore, config.Database()) _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{}, config.Database()) diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index ff1cab4f3c6..a5d3ee984da 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -152,8 +152,7 @@ func TestPipelineORM_Integration(t *testing.T) { orm := pipeline.NewORM(db, logger.TestLogger(t), cfg.Database(), cfg.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, logger.TestLogger(t), cfg.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{Client: evmtest.NewEthClientMockWithDefaultChain(t), DB: db, GeneralConfig: config, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) runner := pipeline.NewRunner(orm, btORM, config.JobPipeline(), cfg.WebServer(), legacyChains, nil, nil, lggr, nil, nil) jobORM := NewTestORM(t, db, legacyChains, orm, btORM, keyStore, cfg.Database()) @@ -161,13 +160,11 @@ func TestPipelineORM_Integration(t *testing.T) { dbSpec := makeVoterTurnoutOCRJobSpec(t, transmitterAddress, bridge.Name.String(), bridge2.Name.String()) // Need a job in order to create a run - err = jobORM.CreateJob(dbSpec) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(dbSpec)) var pipelineSpecs []pipeline.Spec sql := `SELECT * FROM pipeline_specs;` - err = db.Select(&pipelineSpecs, sql) - require.NoError(t, err) + require.NoError(t, db.Select(&pipelineSpecs, sql)) require.Len(t, pipelineSpecs, 1) require.Equal(t, dbSpec.PipelineSpecID, pipelineSpecs[0].ID) pipelineSpecID := pipelineSpecs[0].ID diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index 8418ae999bb..72a20a476e3 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -53,19 +53,19 @@ var monitoringEndpoint = telemetry.MonitoringEndpointGenerator(&telemetry.NoopAg func TestRunner(t *testing.T) { db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, pgtest.NewQConfig(true)) - kb, err := keyStore.OCR().Create() - require.NoError(t, err) + ethKeyStore := keyStore.Eth() _, transmitterAddress := cltest.MustInsertRandomKey(t, ethKeyStore, 0) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) config := configtest2.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - t := true - c.P2P.V1.Enabled = &t + c.P2P.V1.Enabled = ptr(true) c.P2P.V1.DefaultBootstrapPeers = &[]string{ "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", "/dns4/chain.link/tcp/1235/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", } + kb, err := keyStore.OCR().Create() + require.NoError(t, err) kbid := models.MustSha256HashFromHex(kb.ID()) c.OCR.KeyBundleID = &kbid taddress := ethkey.EIP55AddressFromAddress(transmitterAddress) @@ -82,8 +82,7 @@ func TestRunner(t *testing.T) { pipelineORM := pipeline.NewORM(db, logger.TestLogger(t), config.Database(), config.JobPipeline().MaxSuccessfulRuns()) btORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) c := clhttptest.NewTestLocalOnlyHTTPClient() runner := pipeline.NewRunner(pipelineORM, btORM, config.JobPipeline(), config.WebServer(), legacyChains, nil, nil, logger.TestLogger(t), c, c) @@ -119,8 +118,7 @@ func TestRunner(t *testing.T) { // Need a job in order to create a run jb := MakeVoterTurnoutOCRJobSpecWithHTTPURL(t, transmitterAddress, httpURL, bridgeVT.Name.String(), bridgeER.Name.String()) - err = jobORM.CreateJob(jb) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(jb)) require.NotNil(t, jb.PipelineSpec) m, err := bridges.MarshalBridgeMetaData(big.NewInt(10), big.NewInt(100)) @@ -175,8 +173,7 @@ func TestRunner(t *testing.T) { ds1 [type=bridge name="%s"]; """ `, bridge.Name.String())) - err = jobORM.CreateJob(jb) - require.NoError(t, err) + require.NoError(t, jobORM.CreateJob(jb)) // Should not be able to delete a bridge in use. jids, err := jobORM.FindJobIDsWithBridge(bridge.Name.String()) require.NoError(t, err) @@ -196,7 +193,7 @@ func TestRunner(t *testing.T) { // Reference a different one legacyChains := cltest.NewLegacyChainsWithMockChain(t, nil, config) - jb, err2 := ocr.ValidatedOracleSpecToml(legacyChains, fmt.Sprintf(` + jb, err := ocr.ValidatedOracleSpecToml(legacyChains, fmt.Sprintf(` type = "offchainreporting" schemaVersion = 1 evmChainID = 0 @@ -219,7 +216,7 @@ func TestRunner(t *testing.T) { answer1 [type=median index=0]; """ `, placeHolderAddress.String())) - require.NoError(t, err2) + require.NoError(t, err) // Should error creating it err = jobORM.CreateJob(&jb) require.Error(t, err) @@ -689,7 +686,7 @@ ds1 -> ds1_parse; serv := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { time.Sleep(1 * time.Millisecond) res.WriteHeader(http.StatusOK) - _, err = res.Write([]byte(`{"USD":10.1}`)) + _, err := res.Write([]byte(`{"USD":10.1}`)) require.NoError(t, err) })) defer serv.Close() @@ -767,8 +764,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) keyStore := cltest.NewKeyStore(t, app.GetSqlxDB(), pgtest.NewQConfig(true)) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: app.GetSqlxDB(), Client: ethClient, GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) require.NoError(t, app.Start(testutils.Context(t))) var ( @@ -950,8 +946,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) keyStore := cltest.NewKeyStore(t, app.GetSqlxDB(), pgtest.NewQConfig(true)) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: app.GetSqlxDB(), Client: ethClient, GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) require.NoError(t, app.Start(testutils.Context(t))) diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index de6ca541e59..f35aa50ba4d 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -94,8 +94,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { Return(nil).Maybe() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) t.Run("should respect its dependents", func(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, legacyChains, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) @@ -280,8 +279,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) relayExtenders := evmtest.NewChainRelayExtenders(t, testopts) assert.Equal(t, relayExtenders.Len(), 1) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) chain := evmtest.MustGetDefaultChain(t, legacyChains) evmRelayer := evmrelayer.NewRelayer(testopts.DB, chain, testopts.GeneralConfig.Database(), lggr, keyStore, pg.NewNullEventBroadcaster()) @@ -306,7 +304,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { jobOCR2VRF.Type: delegateOCR2, }, db, lggr, nil) - err = spawner.CreateJob(jobOCR2VRF) + err := spawner.CreateJob(jobOCR2VRF) require.NoError(t, err) jobSpecID := jobOCR2VRF.ID delegateOCR2.jobID = jobOCR2VRF.ID diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index c3fadc8bcf4..6b9bb815a89 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -44,8 +44,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( lbMock.On("AddDependents", 1).Maybe() j := cltest.MustInsertKeeperJob(t, db, korm, cltest.NewEIP55Address(), cltest.NewEIP55Address()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, LogBroadcaster: lbMock, GeneralConfig: cfg, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) ch := evmtest.MustGetDefaultChain(t, legacyChains) jpv2 := cltest.NewJobPipelineV2(t, cfg.WebServer(), cfg.JobPipeline(), cfg.Database(), legacyChains, db, keyStore, nil, nil) contractAddress := j.KeeperSpec.ContractAddress.Address() diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 0f15f3949ba..c971152df3a 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -76,8 +76,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Maybe().Return(&evmtypes.Head{Number: 1, Hash: utils.NewHash()}, nil) txm := txmmocks.NewMockEvmTxManager(t) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{TxManager: txm, DB: db, Client: ethClient, KeyStore: keyStore.Eth(), GeneralConfig: cfg, GasEstimator: estimator}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jpv2 := cltest.NewJobPipelineV2(t, cfg.WebServer(), cfg.JobPipeline(), cfg.Database(), legacyChains, db, keyStore, nil, nil) ch := evmtest.MustGetDefaultChain(t, legacyChains) orm := keeper.NewORM(db, logger.TestLogger(t), ch.Config().Database()) @@ -85,9 +84,8 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain lggr := logger.TestLogger(t) executer := keeper.NewUpkeepExecuter(job, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), job.KeeperSpec.FromAddress.Address()) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), registry) - err = executer.Start(testutils.Context(t)) + require.NoError(t, executer.Start(testutils.Context(t))) t.Cleanup(func() { executer.Close() }) - require.NoError(t, err) return db, cfg, ethClient, executer, registry, upkeep, job, jpv2, txm, keyStore, ch, orm } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 9c1faca0c30..2a8fea38efe 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -371,7 +371,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job, qopts ...pg.QOpt) ([]job.ServiceC if err != nil { return nil, err } - if err := libocr2.SanityCheckLocalConfig(lc); err != nil { + if err = libocr2.SanityCheckLocalConfig(lc); err != nil { return nil, err } lggr.Infow("OCR2 job using local config", diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index bd442e67c00..e78af2e19b4 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -45,8 +45,7 @@ func TestGetEVMEffectiveTransmitterID(t *testing.T) { txManager := txmmocks.NewMockEvmTxManager(t) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth(), TxManager: txManager}) require.True(t, relayExtenders.Len() > 0) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) type testCase struct { name string diff --git a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go index 47351327db3..bedfdc92d19 100644 --- a/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go +++ b/core/services/ocr2/plugins/functions/integration_tests/v1/internal/testutils.go @@ -113,19 +113,19 @@ func CreateAndFundSubscriptions(t *testing.T, b *backends.SimulatedBackend, owne allowed, err := allowListContract.HasAccess(nilOpts, owner.From, []byte{}) require.NoError(t, err) if !allowed { - message, err := allowListContract.GetMessage(nilOpts, owner.From, owner.From) - require.NoError(t, err) - privateKey, err := crypto.HexToECDSA(allowListPrivateKey[2:]) - require.NoError(t, err) - flatSignature, err := crypto.Sign(message[:], privateKey) - require.NoError(t, err) + message, err2 := allowListContract.GetMessage(nilOpts, owner.From, owner.From) + require.NoError(t, err2) + privateKey, err2 := crypto.HexToECDSA(allowListPrivateKey[2:]) + require.NoError(t, err2) + flatSignature, err2 := crypto.Sign(message[:], privateKey) + require.NoError(t, err2) var r [32]byte copy(r[:], flatSignature[:32]) var s [32]byte copy(s[:], flatSignature[32:64]) v := flatSignature[65] - _, err = allowListContract.AcceptTermsOfService(owner, owner.From, owner.From, r, s, v) - require.NoError(t, err) + _, err2 = allowListContract.AcceptTermsOfService(owner, owner.From, owner.From, r, s, v) + require.NoError(t, err2) } _, err = routerContract.CreateSubscription(owner) diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index 0863226e647..4c03ce16ef8 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -522,8 +522,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { bridgeORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jorm := job.NewORM(db, legacyChains, porm, bridgeORM, keyStore, lggr, config.Database()) defer func() { assert.NoError(t, jorm.Close()) }() @@ -548,7 +547,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { MaxTaskDuration: models.Interval(1 * time.Minute), } - err = jorm.CreateJob(&keeperJob) + err := jorm.CreateJob(&keeperJob) require.NoError(t, err) require.Equal(t, job.Keeper, keeperJob.Type) @@ -625,8 +624,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { bridgeORM := bridges.NewORM(db, lggr, config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: config, KeyStore: keyStore.Eth()}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jorm := job.NewORM(db, legacyChains, porm, bridgeORM, keyStore, lggr, config.Database()) defer func() { assert.NoError(t, jorm.Close()) }() @@ -650,7 +648,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { MaxTaskDuration: models.Interval(1 * time.Minute), } - err = jorm.CreateJob(&drJob) + err := jorm.CreateJob(&drJob) require.NoError(t, err) require.Equal(t, job.DirectRequest, drJob.Type) diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 1b13289289e..2554315a46c 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -44,8 +44,7 @@ func newRunner(t testing.TB, db *sqlx.DB, bridgeORM bridges.ORM, cfg chainlink.G lggr := logger.TestLogger(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) orm := mocks.NewORM(t) q := pg.NewQ(db, lggr, cfg.Database()) @@ -482,8 +481,7 @@ func Test_PipelineRunner_HandleFaultsPersistRun(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) lggr := logger.TestLogger(t) r := pipeline.NewRunner(orm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ethKeyStore, nil, lggr, nil, nil) diff --git a/core/services/pipeline/task.eth_call_test.go b/core/services/pipeline/task.eth_call_test.go index 8d7f128a0d4..b8896488e2d 100644 --- a/core/services/pipeline/task.eth_call_test.go +++ b/core/services/pipeline/task.eth_call_test.go @@ -258,11 +258,9 @@ func TestETHCallTask(t *testing.T) { db := pgtest.NewSqlxDB(t) var legacyChains evm.LegacyChainContainer - var err error if test.expectedErrorCause != nil || test.expectedErrorContains != "" { exts := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, TxManager: txManager, KeyStore: keyStore}) - legacyChains, err = evmrelay.NewLegacyChainsFromRelayerExtenders(exts) - require.NoError(t, err) + legacyChains = evmrelay.NewLegacyChainsFromRelayerExtenders(exts) } else { legacyChains = cltest.NewLegacyChainsWithMockChain(t, ethClient, cfg) } diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index 83f855c9982..d465c16f8fd 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -575,8 +575,7 @@ func TestETHTxTask(t *testing.T) { relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, TxManager: txManager, KeyStore: keyStore}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) test.setupClientMocks(keyStore, txManager) task.HelperSetDependencies(legacyChains, keyStore, test.specGasLimit, pipeline.DirectRequestJobType) diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 499494c2211..5b3a3535c51 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -42,8 +42,7 @@ type ChainRelayerExtenders struct { var _ EVMChainRelayerExtenderSlicer = &ChainRelayerExtenders{} -func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) (*evmchain.LegacyChains, error) { - +func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) *evmchain.LegacyChains { m := make(map[string]evmchain.Chain) var dflt evmchain.Chain for _, r := range exts.Slice() { @@ -52,14 +51,11 @@ func NewLegacyChainsFromRelayerExtenders(exts EVMChainRelayerExtenderSlicer) (*e dflt = r.Chain() } } - l, err := evmchain.NewLegacyChains(exts.AppConfig(), m) - if err != nil { - return nil, err - } + l := evmchain.NewLegacyChains(m, exts.AppConfig().EVMConfigs()) if dflt != nil { l.SetDefault(dflt) } - return l, nil + return l } func newChainRelayerExtsFromSlice(exts []*ChainRelayerExt, appConfig evm.AppConfig) *ChainRelayerExtenders { diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index dba1d818ed4..b26e5511c16 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -79,8 +79,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv txm := txmmocks.NewMockEvmTxManager(t) ks := keystore.New(db, utils.FastScryptParams, lggr, cfg.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{LogBroadcaster: lb, KeyStore: ks.Eth(), Client: ec, DB: db, GeneralConfig: cfg, TxManager: txm}) - legacyChains, err := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) - require.NoError(t, err) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) jrm := job.NewORM(db, legacyChains, prm, btORM, ks, lggr, cfg.Database()) t.Cleanup(func() { jrm.Close() }) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index 557ceb7b7ce..26e061b164f 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -8,7 +8,6 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" @@ -91,8 +90,7 @@ func TestResolver_ETHKeys(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) m := map[string]evm.Chain{states[0].EVMChainID.String(): f.Mocks.chain} - legacyEVMChains, err := evm.NewLegacyChains(cfg, m) - require.NoError(t, err) + legacyEVMChains := evm.NewLegacyChains(m, cfg.EVMConfigs()) f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) From 3bf936a88c277191227e9175c756305e84b16bd2 Mon Sep 17 00:00:00 2001 From: Amir Y <83904651+amirylm@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:16:56 +0300 Subject: [PATCH 04/15] HasFilter to check whether some filter was loaded by the poller (#10469) Co-authored-by: Domino Valdano <2644901+reductionista@users.noreply.github.com> --- core/chains/evm/logpoller/disabled.go | 2 ++ core/chains/evm/logpoller/log_poller.go | 10 ++++++++++ core/chains/evm/logpoller/log_poller_test.go | 7 +++++++ core/chains/evm/logpoller/mocks/log_poller.go | 14 ++++++++++++++ 4 files changed, 33 insertions(+) diff --git a/core/chains/evm/logpoller/disabled.go b/core/chains/evm/logpoller/disabled.go index 80a5550b0a5..602bd5cec27 100644 --- a/core/chains/evm/logpoller/disabled.go +++ b/core/chains/evm/logpoller/disabled.go @@ -37,6 +37,8 @@ func (disabled) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { return E func (disabled) UnregisterFilter(name string, qopts ...pg.QOpt) error { return ErrDisabled } +func (disabled) HasFilter(name string) bool { return false } + func (disabled) LatestBlock(qopts ...pg.QOpt) (int64, error) { return -1, ErrDisabled } func (disabled) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) { diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index 60767970289..69a3143859f 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -36,6 +36,7 @@ type LogPoller interface { ReplayAsync(fromBlock int64) RegisterFilter(filter Filter, qopts ...pg.QOpt) error UnregisterFilter(name string, qopts ...pg.QOpt) error + HasFilter(name string) bool LatestBlock(qopts ...pg.QOpt) (int64, error) GetBlocksRange(ctx context.Context, numbers []uint64, qopts ...pg.QOpt) ([]LogPollerBlock, error) @@ -258,6 +259,15 @@ func (lp *logPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { return nil } +// HasFilter returns true if the log poller has an active filter with the given name. +func (lp *logPoller) HasFilter(name string) bool { + lp.filterMu.RLock() + defer lp.filterMu.RUnlock() + + _, ok := lp.filters[name] + return ok +} + func (lp *logPoller) Filter(from, to *big.Int, bh *common.Hash) ethereum.FilterQuery { lp.filterMu.Lock() defer lp.filterMu.Unlock() diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 17df4dc6291..c434d18c999 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -760,6 +760,13 @@ func TestLogPoller_LoadFilters(t *testing.T) { require.True(t, ok) assert.True(t, filter.Contains(&filter3)) assert.True(t, filter3.Contains(&filter)) + + t.Run("HasFilter", func(t *testing.T) { + assert.True(t, th.LogPoller.HasFilter("first Filter")) + assert.True(t, th.LogPoller.HasFilter("second Filter")) + assert.True(t, th.LogPoller.HasFilter("third Filter")) + assert.False(t, th.LogPoller.HasFilter("fourth Filter")) + }) } func TestLogPoller_GetBlocks_Range(t *testing.T) { diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index 9e96947abc7..3c30454a4f7 100644 --- a/core/chains/evm/logpoller/mocks/log_poller.go +++ b/core/chains/evm/logpoller/mocks/log_poller.go @@ -68,6 +68,20 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts return r0, r1 } +// HasFilter provides a mock function with given fields: name +func (_m *LogPoller) HasFilter(name string) bool { + ret := _m.Called(name) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(name) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + // HealthReport provides a mock function with given fields: func (_m *LogPoller) HealthReport() map[string]error { ret := _m.Called() From 94d05b789a97ba71b233f1cce9ef020f50720c4b Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal <71980293+infiloop2@users.noreply.github.com> Date: Wed, 6 Sep 2023 13:55:25 +0100 Subject: [PATCH 05/15] Allow burst in log recoverer when it lags (#10479) * Allow burst in log recoverer when it lags * add test * more tests * update * improve test * update test messages --- .../ocr2keeper/evm21/logprovider/recoverer.go | 9 +- .../evm21/logprovider/recoverer_test.go | 86 ++++++++++++++++++- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index 5acfa1ee0c8..7a7dbbe46be 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -29,7 +29,8 @@ var ( GCInterval = RecoveryCacheTTL recoveryBatchSize = 10 - recoveryLogsBuffer = int64(50) + recoveryLogsBuffer = int64(200) + recoveryLogsBurst = int64(500) ) type LogRecoverer interface { @@ -318,6 +319,12 @@ func (r *logRecoverer) recoverFilter(ctx context.Context, f upkeepFilter, startB start = startBlock } end := start + recoveryLogsBuffer + if offsetBlock-end > 100*recoveryLogsBuffer { + // If recoverer is lagging by a lot (more than 100x recoveryLogsBuffer), allow + // a range of recoveryLogsBurst + // Exploratory: Store lastRePollBlock in DB to prevent bursts during restarts + end = start + recoveryLogsBurst + } if end > offsetBlock { end = offsetBlock } diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 7f01434c2b9..0a993831b7b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -226,6 +226,7 @@ func TestLogRecoverer_Recover(t *testing.T) { logsErr error recoverErr error proposalsWorkIDs []string + lastRePollBlocks []int64 }{ { "no filters", @@ -239,6 +240,7 @@ func TestLogRecoverer_Recover(t *testing.T) { nil, nil, []string{}, + []int64{}, }, { "latest block error", @@ -252,6 +254,7 @@ func TestLogRecoverer_Recover(t *testing.T) { nil, fmt.Errorf("test error"), []string{}, + []int64{}, }, { "states error", @@ -280,6 +283,7 @@ func TestLogRecoverer_Recover(t *testing.T) { nil, nil, []string{}, + []int64{0}, }, { "get logs error", @@ -301,11 +305,12 @@ func TestLogRecoverer_Recover(t *testing.T) { fmt.Errorf("test error"), nil, []string{}, + []int64{0}, }, { "happy flow", 100, - 200, + 500, nil, []upkeepFilter{ { @@ -321,7 +326,15 @@ func TestLogRecoverer_Recover(t *testing.T) { topics: []common.Hash{ common.HexToHash("0x2"), }, - configUpdateBlock: 150, // should be filtered out + configUpdateBlock: 450, // should be filtered out + }, + { + upkeepID: big.NewInt(3), + addr: common.HexToAddress("0x2").Bytes(), + topics: []common.Hash{ + common.HexToHash("0x2"), + }, + lastRePollBlock: 450, // should be filtered out, as its higher than latest-lookback }, }, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, @@ -337,6 +350,68 @@ func TestLogRecoverer_Recover(t *testing.T) { nil, nil, []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, + []int64{200, 0, 450}, + }, + { + "lastRePollBlock updated with burst when lagging behind", + 100, + 50000, + nil, + []upkeepFilter{ + { + upkeepID: big.NewInt(1), + addr: common.HexToAddress("0x1").Bytes(), + topics: []common.Hash{ + common.HexToHash("0x1"), + }, + lastRePollBlock: 100, // Should be updated with burst + }, + }, + []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, + nil, + []logpoller.Log{ + { + BlockNumber: 2, + TxHash: common.HexToHash("0x111"), + LogIndex: 1, + BlockHash: common.HexToHash("0x2"), + }, + }, + nil, + nil, + []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, + []int64{600}, + }, + { + "recovery starts at configUpdateBlock if higher than lastRePollBlock", + 100, + 5000, + nil, + []upkeepFilter{ + { + upkeepID: big.NewInt(1), + addr: common.HexToAddress("0x1").Bytes(), + topics: []common.Hash{ + common.HexToHash("0x1"), + }, + lastRePollBlock: 100, + configUpdateBlock: 500, + }, + }, + []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, + nil, + []logpoller.Log{ + { + BlockNumber: 2, + TxHash: common.HexToHash("0x111"), + LogIndex: 1, + BlockHash: common.HexToHash("0x2"), + }, + }, + nil, + nil, + []string{"84c83c79c2be2c3eabd8d35986a2a798d9187564d7f4f8f96c5a0f40f50bed3f"}, + []int64{700}, // should be configUpdateBlock + recoveryLogsBuffer }, } @@ -356,6 +431,13 @@ func TestLogRecoverer_Recover(t *testing.T) { return } require.NoError(t, err) + for i, active := range tc.active { + filters := filterStore.GetFilters(func(f upkeepFilter) bool { + return f.upkeepID.String() == active.upkeepID.String() + }) + require.Equal(t, 1, len(filters)) + require.Equal(t, tc.lastRePollBlocks[i], filters[0].lastRePollBlock) + } proposals, err := recoverer.GetRecoveryProposals(ctx) require.NoError(t, err) From e43bdf46327f6d76c7d87602a0793cc94f211d2b Mon Sep 17 00:00:00 2001 From: Amir Y <83904651+amirylm@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:47:35 +0300 Subject: [PATCH 06/15] Update ocr2keepers v0.7.20 (#10486) * update ocr2keepers * go mod tidy --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index d9f2cc7c9c3..4fb609f851a 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -19,7 +19,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.20 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 26a31aafde8..fbd5868834b 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.20 h1:1FOeJ0p4mWHqJiX01v/J2S1C1LhU8iqJM1hDcD38aZU= +github.com/smartcontractkit/ocr2keepers v0.7.20/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/go.mod b/go.mod index 7d5b1757992..2f7c8aca670 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,7 @@ require ( github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.20 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e diff --git a/go.sum b/go.sum index a0243097bc0..ea1158e13df 100644 --- a/go.sum +++ b/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.20 h1:1FOeJ0p4mWHqJiX01v/J2S1C1LhU8iqJM1hDcD38aZU= +github.com/smartcontractkit/ocr2keepers v0.7.20/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index d3a8b5a19cb..47e74c46dd3 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -23,7 +23,7 @@ require ( github.com/smartcontractkit/chainlink-testing-framework v1.16.1-0.20230829222228-4afd1b3d385c github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 - github.com/smartcontractkit/ocr2keepers v0.7.19 + github.com/smartcontractkit/ocr2keepers v0.7.20 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230829114801-14bf715f805e github.com/smartcontractkit/wasp v0.3.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 5e77b2bddcc..8c5bb51f27c 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2264,8 +2264,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJ github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 h1:rzbqGoScs9VHGnyCKF7AoQEuUfwJnzcKmGIfaczeanA= github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.19 h1:w9CMs1V8pmxdRX6ME98goIRPMuN9DOkfMmZHeDPDQXY= -github.com/smartcontractkit/ocr2keepers v0.7.19/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= +github.com/smartcontractkit/ocr2keepers v0.7.20 h1:1FOeJ0p4mWHqJiX01v/J2S1C1LhU8iqJM1hDcD38aZU= +github.com/smartcontractkit/ocr2keepers v0.7.20/go.mod h1:AjcIEKeNnU7NRlvnuMCTjBIQ1kpW0YHhlFdeDa/3hs0= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= From 3c9cf014f5449a9403408112cc11e8360687c68e Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal <71980293+infiloop2@users.noreply.github.com> Date: Wed, 6 Sep 2023 14:58:05 +0100 Subject: [PATCH 07/15] Remove explicit checkblock too old check and rely on rpc, add a check for checkBlock too new (#10484) * Remove explicit checkblock too old check and rely on rpc * update * update * fix test * fix * update test --- .../ocr2keeper/evm21/encoding/interface.go | 1 + .../evm21/registry_check_pipeline.go | 30 ++++++++++--------- .../evm21/registry_check_pipeline_test.go | 13 ++++---- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go index 4b559e9104e..e0c31f2beea 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/encoding/interface.go @@ -41,6 +41,7 @@ const ( MercuryUnmarshalError PipelineExecutionState = 6 InvalidMercuryRequest PipelineExecutionState = 7 InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses + CheckBlockTooNew PipelineExecutionState = 9 ) type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go index 5cf2dfa0981..bf57ce496a3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline.go @@ -15,12 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/encoding" ) -const ( - // validCheckBlockRange decides the max distance between the check block and the current block - // allowed in checkPipeline - validCheckBlockRange = 128 -) - type checkResult struct { cr []ocr2keepers.CheckResult err error @@ -99,11 +93,11 @@ func (r *EvmRegistry) getBlockHash(blockNumber *big.Int) (common.Hash, error) { // verifyCheckBlock checks that the check block and hash are valid, returns the pipeline execution state and retryable func (r *EvmRegistry) verifyCheckBlock(ctx context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { - // verify check block number is not too old + // verify check block number is not in future (can happen when this node is lagging the other members in DON) latestBlock := r.bs.latestBlock.Load() - if int64(latestBlock.Number)-checkBlock.Int64() > validCheckBlockRange { - r.lggr.Warnf("latest block is %d, check block number %s is too old for upkeepId %s", r.bs.latestBlock.Load(), checkBlock, upkeepId) - return encoding.CheckBlockTooOld, false + if checkBlock.Int64() > int64(latestBlock.Number) { + r.lggr.Warnf("latest block is %d, check block number %s is in future for upkeepId %s", r.bs.latestBlock.Load(), checkBlock, upkeepId) + return encoding.CheckBlockTooNew, true // retryable since the block can be found in future } var h string @@ -240,10 +234,18 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U for i, req := range checkReqs { index := indices[i] if req.Error != nil { - // individual upkeep failed in a batch call, retryable - r.lggr.Warnf("error encountered in check result for upkeepId %s: %s", results[index].UpkeepID.String(), req.Error) - results[index].Retryable = true - results[index].PipelineExecutionState = uint8(encoding.RpcFlakyFailure) + // primitive way of checking errors + if strings.Contains(req.Error.Error(), "header not found") { + // Check block not found in RPC, non-retryable error + r.lggr.Warnf("header not found error encountered in check result for upkeepId %s: %s", results[index].UpkeepID.String(), req.Error) + results[index].Retryable = false + results[index].PipelineExecutionState = uint8(encoding.CheckBlockTooOld) + } else { + // individual upkeep failed in a batch call, likely a flay RPC error, consider retryable + r.lggr.Warnf("rpc error encountered in check result for upkeepId %s: %s", results[index].UpkeepID.String(), req.Error) + results[index].Retryable = true + results[index].PipelineExecutionState = uint8(encoding.RpcFlakyFailure) + } } else { var err error results[index], err = r.packer.UnpackCheckResult(payloads[index], *checkResults[i]) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go index 69364396e8b..0cd1a11fcce 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry_check_pipeline_test.go @@ -86,9 +86,9 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { makeEthCall bool }{ { - name: "check block number too told", + name: "check block number too new", checkBlock: big.NewInt(500), - latestBlock: ocr2keepers.BlockKey{Number: 800}, + latestBlock: ocr2keepers.BlockKey{Number: 400}, upkeepId: big.NewInt(12345), checkHash: common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83"), payload: ocr2keepers.UpkeepPayload{ @@ -96,7 +96,8 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { Trigger: ocr2keepers.NewTrigger(500, common.HexToHash("0x5bff03de234fe771ac0d685f9ee0fb0b757ea02ec9e6f10e8e2ee806db1b6b83")), WorkID: "work", }, - state: encoding.CheckBlockTooOld, + state: encoding.CheckBlockTooNew, + retryable: true, }, { name: "for an invalid check block number, if hash does not match the check hash, return CheckBlockInvalid", @@ -368,7 +369,7 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { BlockNumber: 550, } - trigger0 := ocr2keepers.NewTrigger(150, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) + trigger0 := ocr2keepers.NewTrigger(590, common.HexToHash("0x1c77db0abe32327cf3ea9de2aadf79876f9e6b6dfcee9d4719a8a2dc8ca289d0")) trigger1 := ocr2keepers.NewLogTrigger(560, common.HexToHash("0x9840e5b709bfccf6a1b44f34c884bc39403f57923f3f5ead6243cc090546b857"), extension1) trigger2 := ocr2keepers.NewLogTrigger(570, common.HexToHash("0x1222d75217e2dd461cc77e4091c37abe76277430d97f1963a822b4e94ebb83fc"), extension2) @@ -412,8 +413,8 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { latestBlock: ocr2keepers.BlockKey{Number: 580}, results: []ocr2keepers.CheckResult{ { - PipelineExecutionState: uint8(encoding.CheckBlockTooOld), - Retryable: false, + PipelineExecutionState: uint8(encoding.CheckBlockTooNew), + Retryable: true, Eligible: false, IneligibilityReason: 0, UpkeepID: uid0, From 37f38803fb4d39a63284401ed6b60a89eb66b572 Mon Sep 17 00:00:00 2001 From: Sergei Drugalev Date: Wed, 6 Sep 2023 16:27:53 +0200 Subject: [PATCH 08/15] Using minmax heap for Mercury transmission queue to evict oldest transmission correctly (#10427) * Using minmax heap for Mercury transmission queue to evict oldest transmission correctly * go mod tidy * go mod tidy everywhere --- core/scripts/go.mod | 1 + core/scripts/go.sum | 2 ++ core/services/relay/evm/mercury/queue.go | 29 ++++++------------- core/services/relay/evm/mercury/queue_test.go | 14 ++++----- go.mod | 1 + go.sum | 2 ++ integration-tests/go.mod | 1 + integration-tests/go.sum | 2 ++ 8 files changed, 23 insertions(+), 29 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 4fb609f851a..738d21ddb73 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -98,6 +98,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/esote/minmaxheap v1.0.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index fbd5868834b..9d919d1ac72 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -320,6 +320,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= +github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go index 743a6553dff..44042c57725 100644 --- a/core/services/relay/evm/mercury/queue.go +++ b/core/services/relay/evm/mercury/queue.go @@ -1,13 +1,13 @@ package mercury import ( - "container/heap" "context" "errors" "fmt" "sync" "time" + heap "github.com/esote/minmaxheap" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -59,11 +59,6 @@ type TransmitQueue struct { type Transmission struct { Req *pb.TransmitRequest // the payload to transmit ReportCtx ocrtypes.ReportContext // contains priority information (latest epoch/round wins) - - // The index is needed by update and is maintained by the heap.Interface - // methods - // It should NOT be set manually - index int // the index of the item in the heap } // maxlen controls how many items will be stored in the queue @@ -97,13 +92,13 @@ func (tq *TransmitQueue) Push(req *pb.TransmitRequest, reportCtx ocrtypes.Report if tq.maxlen != 0 && tq.pq.Len() == tq.maxlen { // evict oldest entry to make room tq.lggr.Criticalf("Transmit queue is full; dropping oldest transmission (reached max length of %d)", tq.maxlen) - removed := heap.Remove(tq.pq, tq.pq.Len()-1) + removed := heap.PopMax(tq.pq) if transmission, ok := removed.(*Transmission); ok { tq.asyncDeleter.AsyncDelete(transmission.Req) } } - heap.Push(tq.pq, &Transmission{req, reportCtx, -1}) + heap.Push(tq.pq, &Transmission{req, reportCtx}) tq.cond.Signal() return true @@ -231,6 +226,10 @@ func (pq priorityQueue) Less(i, j int) bool { pq[i].ReportCtx.ReportTimestamp.Round > pq[j].ReportCtx.ReportTimestamp.Round } +func (pq priorityQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] +} + func (pq *priorityQueue) Pop() any { n := len(*pq) if n == 0 { @@ -238,21 +237,11 @@ func (pq *priorityQueue) Pop() any { } old := *pq item := old[n-1] - old[n-1] = nil // avoid memory leak - item.index = -1 // for safety + old[n-1] = nil // avoid memory leak *pq = old[0 : n-1] return item } func (pq *priorityQueue) Push(x any) { - n := len(*pq) - item := x.(*Transmission) - item.index = n - *pq = append(*pq, item) -} - -func (pq priorityQueue) Swap(i, j int) { - pq[i], pq[j] = pq[j], pq[i] - pq[i].index = i - pq[j].index = j + *pq = append(*pq, x.(*Transmission)) } diff --git a/core/services/relay/evm/mercury/queue_test.go b/core/services/relay/evm/mercury/queue_test.go index 9fa2520147d..de2f64f9fe9 100644 --- a/core/services/relay/evm/mercury/queue_test.go +++ b/core/services/relay/evm/mercury/queue_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -81,7 +80,7 @@ func Test_Queue(t *testing.T) { }) t.Run("transmit queue is more than 50% full", func(t *testing.T) { - transmitQueue.Push(testTransmissions[2].tr, testTransmissions[0].ctx) + transmitQueue.Push(testTransmissions[2].tr, testTransmissions[2].ctx) report := transmitQueue.HealthReport() assert.Equal(t, report[transmitQueue.Name()].Error(), "transmit priority queue is greater than 50% full (4/7)") }) @@ -92,21 +91,18 @@ func Test_Queue(t *testing.T) { }) t.Run("transmit queue is full and evicts the oldest transmission", func(t *testing.T) { - // There is a bug with queue eviction where the evicted transmission is NOT the oldest. - // TODO: MERC-1049 Once this bug is fixed, replace the expectation with the one below. - // deleter.On("AsyncDelete", testTransmissions[0].tr).Once() - deleter.On("AsyncDelete", mock.Anything).Once() + deleter.On("AsyncDelete", testTransmissions[0].tr).Once() - // add 5 more transmissions to overflow the queue + // add 5 more transmissions to overflow the queue by 1 for i := 0; i < 5; i++ { transmitQueue.Push(testTransmissions[1].tr, testTransmissions[1].ctx) } + // expecting testTransmissions[0] to get evicted and not present in the queue anymore testutils.WaitForLogMessage(t, observedLogs, "Transmit queue is full; dropping oldest transmission (reached max length of 7)") for i := 0; i < 7; i++ { tr := transmitQueue.BlockingPop() - // TODO: Should be tr.Req instead of tr. - assert.NotEqual(t, tr, testTransmissions[0].tr) + assert.NotEqual(t, tr.Req, testTransmissions[0].tr) } }) diff --git a/go.mod b/go.mod index 2f7c8aca670..730a30daa16 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e + github.com/esote/minmaxheap v1.0.0 github.com/ethereum/go-ethereum v1.12.0 github.com/fatih/color v1.15.0 github.com/fxamacker/cbor/v2 v2.4.0 diff --git a/go.sum b/go.sum index ea1158e13df..152a27cad3e 100644 --- a/go.sum +++ b/go.sum @@ -314,6 +314,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= +github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 47e74c46dd3..c7e8ec794a2 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -131,6 +131,7 @@ require ( github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/esote/minmaxheap v1.0.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 8c5bb51f27c..d43c4163142 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -896,6 +896,8 @@ github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= +github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= From 1176a8cd6da53cad6b4f3bfeb2e42aa23b469deb Mon Sep 17 00:00:00 2001 From: Amir Y <83904651+amirylm@users.noreply.github.com> Date: Wed, 6 Sep 2023 17:40:16 +0300 Subject: [PATCH 09/15] Upkeep filters life cycle: avoid replying logs for existing filters (#10470) * filters life cycle: avoid replying logs for existing filters TODO: tests * fix test * use config update block if not too old * small fix + align tests and logs * added mocks for HasFilter --- .../evm21/logprovider/provider_life_cycle.go | 27 +++++++++---- .../logprovider/provider_life_cycle_test.go | 40 +++++++++++++++---- .../evm21/logprovider/provider_test.go | 1 + 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go index 8a21637241a..0e2c0068bab 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle.go @@ -83,11 +83,6 @@ func (p *logEventProvider) RegisterFilter(ctx context.Context, opts FilterOption p.lggr.Debugf("filter for upkeep with id %s already registered with the same config", upkeepID.String()) return nil } - // removing filter so we can recreate it with updated values - err := p.poller.UnregisterFilter(p.filterName(currentFilter.upkeepID)) - if err != nil { - return fmt.Errorf("failed to unregister upkeep filter %s for update: %w", upkeepID.String(), err) - } filter = *currentFilter } else { // new filter filter = upkeepFilter{ @@ -115,17 +110,35 @@ func (p *logEventProvider) register(ctx context.Context, lpFilter logpoller.Filt if err != nil { return fmt.Errorf("failed to get latest block while registering filter: %w", err) } + lggr := p.lggr.With("upkeepID", ufilter.upkeepID.String()) + logPollerHasFilter := p.poller.HasFilter(lpFilter.Name) + if logPollerHasFilter { + lggr.Debugw("Upserting upkeep filter") + // removing filter so we can recreate it with updated values + err := p.poller.UnregisterFilter(lpFilter.Name) + if err != nil { + return fmt.Errorf("failed to upsert (unregister) upkeep filter %s: %w", ufilter.upkeepID.String(), err) + } + } if err := p.poller.RegisterFilter(lpFilter); err != nil { return err } p.filterStore.AddActiveUpkeeps(ufilter) + if logPollerHasFilter { + // already registered, no need to backfill + return nil + } backfillBlock := latest - int64(LogBackfillBuffer) if backfillBlock < 1 { // New chain, backfill from start backfillBlock = 1 } - // TODO: Optimise to do backfill from ufilter.configUpdateBlock only for new filters - // if it is not too old + if int64(ufilter.configUpdateBlock) > backfillBlock { + // backfill from config update block in case it is not too old + backfillBlock = int64(ufilter.configUpdateBlock) + } + // NOTE: replys are planned to be done as part of RegisterFilter within logpoller + lggr.Debugw("Backfilling logs for new upkeep filter", "backfillBlock", backfillBlock) p.poller.ReplayAsync(backfillBlock) return nil diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go index c42e1c3bac3..e51871c4784 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_life_cycle_test.go @@ -23,6 +23,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { errored bool upkeepID *big.Int upkeepCfg LogTriggerConfig + hasFilter bool + replyed bool cfgUpdateBlock uint64 mockPoller bool unregister bool @@ -35,6 +37,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + false, + true, uint64(1), true, false, @@ -44,6 +48,8 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { true, big.NewInt(111), LogTriggerConfig{}, + false, + false, uint64(0), false, false, @@ -56,18 +62,22 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{}, 32)), }, + false, + false, uint64(2), false, false, }, { - "existing config", + "existing config with old block", true, big.NewInt(111), LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + true, + false, uint64(0), true, false, @@ -80,23 +90,37 @@ func TestLogEventProvider_LifeCycle(t *testing.T) { ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), }, + true, + false, uint64(2), true, true, }, } - mp := new(mocks.LogPoller) - mp.On("RegisterFilter", mock.Anything).Return(nil) - mp.On("UnregisterFilter", mock.Anything).Return(nil) - mp.On("LatestBlock", mock.Anything).Return(int64(0), nil) - mp.On("ReplayAsync", mock.Anything).Return(nil) - p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) + p := NewLogProvider(logger.TestLogger(t), nil, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + + if tc.mockPoller { + lp := new(mocks.LogPoller) + lp.On("RegisterFilter", mock.Anything).Return(nil) + lp.On("UnregisterFilter", mock.Anything).Return(nil) + lp.On("LatestBlock", mock.Anything).Return(int64(0), nil) + lp.On("HasFilter", p.filterName(tc.upkeepID)).Return(tc.hasFilter).Times(1) + if tc.replyed { + lp.On("ReplayAsync", mock.Anything).Return(nil).Times(1) + } else { + lp.On("ReplayAsync", mock.Anything).Return(nil).Times(0) + } + p.lock.Lock() + p.poller = lp + p.lock.Unlock() + } + err := p.RegisterFilter(ctx, FilterOptions{ UpkeepID: tc.upkeepID, TriggerConfig: tc.upkeepCfg, @@ -120,6 +144,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { mp := new(mocks.LogPoller) mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("UnregisterFilter", mock.Anything).Return(nil) + mp.On("HasFilter", mock.Anything).Return(false) mp.On("LatestBlock", mock.Anything).Return(int64(0), nil) mp.On("ReplayAsync", mock.Anything).Return(nil) @@ -146,6 +171,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { newIds, err := p.RefreshActiveUpkeeps() require.NoError(t, err) require.Len(t, newIds, 0) + mp.On("HasFilter", p.filterName(core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt())).Return(true) newIds, err = p.RefreshActiveUpkeeps( core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), core.GenUpkeepID(ocr2keepers.LogTrigger, "1234").BigInt(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go index 159e229a2ff..47070d71aed 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider_test.go @@ -246,6 +246,7 @@ func TestLogEventProvider_ReadLogs(t *testing.T) { mp.On("RegisterFilter", mock.Anything).Return(nil) mp.On("ReplayAsync", mock.Anything).Return() + mp.On("HasFilter", mock.Anything).Return(false) mp.On("UnregisterFilter", mock.Anything, mock.Anything).Return(nil) mp.On("LatestBlock", mock.Anything).Return(int64(1), nil) mp.On("LogsWithSigs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{ From 2ff674b728ff8a1d4d1acafac29cd5b58a1bc5b4 Mon Sep 17 00:00:00 2001 From: Michael Fletcher <36506122+Fletch153@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:46:38 +0100 Subject: [PATCH 10/15] Additional even emitting + sanity checks + version (#10419) * Additional even emitting + sanity checks + version * Cherry picked changes from bugfix/MERC-1618 * Wrappers + gas * Fixed issue with getAvailableRewardPoolIds --------- Co-authored-by: Austin Born --- .../gas-snapshots/llo-feeds.gas-snapshot | 332 +++++++++--------- .../src/v0.8/llo-feeds/VerifierProxy.sol | 15 +- .../src/v0.8/llo-feeds/dev/FeeManager.sol | 90 +++-- .../src/v0.8/llo-feeds/dev/RewardManager.sol | 33 +- .../llo-feeds/dev/interfaces/IFeeManager.sol | 49 +-- .../dev/interfaces/IRewardManager.sol | 8 +- .../interfaces/IVerifierFeeManager.sol | 4 +- .../llo-feeds/interfaces/IVerifierProxy.sol | 2 +- .../test/fee-manager/BaseFeeManager.t.sol | 28 +- .../test/fee-manager/FeeManager.general.t.sol | 10 +- .../FeeManager.getFeeAndReward.t.sol | 36 ++ .../fee-manager/FeeManager.processFee.t.sol | 42 +++ .../reward-manager/BaseRewardManager.t.sol | 1 + .../reward-manager/RewardManager.claim.t.sol | 40 ++- .../test/verifier/VerifierProxyTest.t.sol | 10 + .../generated/fee_manager/fee_manager.go | 185 +++++++++- .../reward_manager/reward_manager.go | 34 +- .../verifier_proxy/verifier_proxy.go | 4 +- ...rapper-dependency-versions-do-not-edit.txt | 6 +- 19 files changed, 646 insertions(+), 283 deletions(-) rename contracts/src/v0.8/llo-feeds/{ => dev}/interfaces/IVerifierFeeManager.sol (87%) diff --git a/contracts/gas-snapshots/llo-feeds.gas-snapshot b/contracts/gas-snapshots/llo-feeds.gas-snapshot index 18499e0f6c2..1a2df6b93e5 100644 --- a/contracts/gas-snapshots/llo-feeds.gas-snapshot +++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot @@ -1,135 +1,143 @@ -FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52609) -FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 25927) -FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 57240) -FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 120182) -FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 28588) -FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 74518) -FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71365) -FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56167) -FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25300) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14621) -FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17579) -FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 90869) -FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56477) -FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52755) -FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49580) -FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78792) -FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46384) +FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52634) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52566) +FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78769) +FeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 25961) +FeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 57252) +FeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 118189) +FeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 28568) +FeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 72501) +FeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 71670) +FeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56292) +FeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 25344) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 14623) +FeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 17581) +FeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 90945) +FeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56524) +FeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52803) +FeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49627) +FeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78817) +FeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46428) FeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17568) -FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54523) -FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12361) -FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41347) -FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 260960) -FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 68464) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49645) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67562) -FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64156) -FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 51987) -FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14641) -FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49771) -FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55510) -FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82724) -FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49623) -FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49581) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17579) -FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50760) +FeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54571) +FeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49581) +FeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12392) +FeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41412) +FeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 259447) +FeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 69018) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49706) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67635) +FeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64232) +FeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 52012) +FeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 14621) +FeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49774) +FeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55561) +FeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82702) +FeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49602) +FeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49604) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 17601) +FeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50826) FeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 52375) -FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30789) -FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50802) -FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17188) +FeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30814) +FeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50827) +FeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17166) FeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41370) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51832) -FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78015) -FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 24103) -FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19814) -FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 197190) -FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17338) -FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 218523) -FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 201471) -FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 120576) -FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 26799) -FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 163879) -FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27360) -FeeManagerProcessFeeTest:test_processFeeNative() (gas: 176574) -FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 121514) -FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29118) -FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 30602) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 184105) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 135624) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 159487) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 94615) -FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 191065) -FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 28471) -FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 28939) -FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 29928) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 35144) -FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 156485) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 55585) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 120542) -FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 37846) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 296517) -FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 279759) -FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 236449) -FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 270220) -FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 71195) -FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 253350) -FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 283979) -FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 300708) -FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 11011) -FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19570) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51879) +FeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78062) +FeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 21892) +FeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19836) +FeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 195521) +FeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17360) +FeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 216708) +FeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 199820) +FeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 118561) +FeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 26811) +FeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 163961) +FeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 27362) +FeeManagerProcessFeeTest:test_processFeeNative() (gas: 174559) +FeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 119521) +FeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 29175) +FeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 244302) +FeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 30610) +FeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 168476) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 182111) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 133607) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 157494) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 94743) +FeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 189049) +FeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 28473) +FeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 28919) +FeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 29914) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 35154) +FeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 154448) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 55617) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 118462) +FeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 37856) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeUnwrappedReports() (gas: 295021) +FeeManagerProcessFeeTest:test_processMultipleLinkAndNativeWrappedReports() (gas: 278263) +FeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 235077) +FeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 268847) +FeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 71419) +FeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 251978) +FeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 282317) +FeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 299043) +FeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 11038) +FeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19548) FeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46281) -FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51089) -FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51057) -FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79188) -FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 46960) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49837) -FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78208) -FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 15198) +FeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51157) +FeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51082) +FeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79236) +FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47004) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49862) +FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78233) +FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 15251) RewardManagerClaimTest:test_claimAllRecipients() (gas: 275763) RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 153306) -RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 330467) +RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 328322) RewardManagerClaimTest:test_claimSingleRecipient() (gas: 88340) -RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 315671) +RewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 313526) RewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 34461) RewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 40491) RewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 86069) RewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 24700) -RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 385336) -RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 138411) +RewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 383191) +RewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 136266) RewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 489469) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 13550) -RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 55574) -RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249515) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20518) -RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249761) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260965) -RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264101) -RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28592) -RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 25013) -RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31098) -RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84397) -RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197492) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11405) +RewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53858) +RewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 249449) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20452) +RewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 249695) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 260899) +RewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 264035) +RewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28526) +RewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 24947) +RewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31032) +RewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84331) +RewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 197426) RewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 279714) RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 509889) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 281833) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 291618) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 281811) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 291640) RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 261589) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 153390) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 153434) RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 131911) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 105334) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 578510) -RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63533) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 28864) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 146842) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18363) -RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24381) -RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 389786) -RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 138427) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 200572) -RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 220442) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 105312) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 576243) +RewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 63555) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 10202) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12680) +RewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 19606) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 29052) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 147218) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 18532) +RewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 24569) +RewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 387641) +RewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 136305) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 198427) +RewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 218297) RewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 191821) RewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 126091) -RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 193950) +RewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 193972) RewardManagerSetRecipientsTest:test_setRewardRecipientFromNonOwnerOrFeeManagerAddress() (gas: 21452) RewardManagerSetRecipientsTest:test_setRewardRecipientTwice() (gas: 193416) RewardManagerSetRecipientsTest:test_setRewardRecipientWeights() (gas: 180711) @@ -138,28 +146,28 @@ RewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroWeight() (gas: 183 RewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 185681) RewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 87113) RewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 110394) -RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 21366) -RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259335) -RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59390) -RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17016) -RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373819) -RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 279281) -RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19727) -RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 219095) -RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 273103) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 245309) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259381) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 148982) -RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259455) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369300) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 258597) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288735) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 261406) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentPartialSet() (gas: 259384) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (gas: 260794) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 259524) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 251916) -RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 250201) +RewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 21388) +RewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259190) +RewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59418) +RewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17038) +RewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 373696) +RewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 279303) +RewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19749) +RewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 218972) +RewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 273125) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 245331) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259403) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 149004) +RewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259477) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 369177) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 258619) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288757) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 261428) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentPartialSet() (gas: 259406) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (gas: 260816) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 259546) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 251938) +RewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 250223) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesAMiddleDigest() (gas: 24155) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyRemovesTheFirstDigest() (gas: 24122) VerificationdeactivateConfigWhenThereAreMultipleDigestsTest:test_correctlyUnsetsDigestsInSequence() (gas: 44043) @@ -174,32 +182,34 @@ VerifierActivateFeedTest:test_revertsIfNoFeedExistsActivate() (gas: 13179) VerifierActivateFeedTest:test_revertsIfNoFeedExistsDeactivate() (gas: 13157) VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17098) VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17153) -VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 391227) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 702466) -VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 687045) -VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 570309) -VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 783120) -VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 579516) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 581327) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 588801) -VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 595828) +VerifierBulkVerifyBillingReport:test_verifyBulkReportWithUnwrappedAndWrappedNativeDefaultsToUnwrapped() (gas: 391378) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndUnwrappedNative() (gas: 700956) +VerifierBulkVerifyBillingReport:test_verifyBulkWithLinkAndWrappedNative() (gas: 685536) +VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 568369) +VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 781180) +VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 578147) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 581753) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 589227) +VerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 596254) VerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 59939) VerifierConstructorTest:test_setsTheCorrectProperties() (gas: 1788491) VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas: 192062) VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113377) VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99613) VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69932) -VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 204824) +VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 204836) VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 109546) -VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1357299) -VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1337313) +VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1439877) +VerifierProxyConstructorTest:test_correctlySetsTheOwner() (gas: 1419891) VerifierProxyConstructorTest:test_correctlySetsVersion() (gas: 6873) VerifierProxyInitializeVerifierTest:test_revertsIfDigestAlreadySet() (gas: 54085) VerifierProxyInitializeVerifierTest:test_revertsIfNotCorrectVerifier() (gas: 13572) VerifierProxyInitializeVerifierTest:test_revertsIfNotOwner() (gas: 17179) VerifierProxyInitializeVerifierTest:test_revertsIfVerifierAlreadyInitialized() (gas: 42069) VerifierProxyInitializeVerifierTest:test_revertsIfZeroAddress() (gas: 10970) -VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10935) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourIERC165Interface() (gas: 13815) +VerifierProxyInitializeVerifierTest:test_setFeeManagerWhichDoesntHonourInterface() (gas: 16301) +VerifierProxyInitializeVerifierTest:test_setFeeManagerZeroAddress() (gas: 10947) VerifierProxyInitializeVerifierTest:test_updatesVerifierIfVerifier() (gas: 53315) VerifierProxySetAccessControllerTest:test_emitsTheCorrectEvent() (gas: 35384) VerifierProxySetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 15105) @@ -209,8 +219,8 @@ VerifierProxyUnsetVerifierTest:test_revertsIfDigestDoesNotExist() (gas: 13141) VerifierProxyUnsetVerifierTest:test_revertsIfNotAdmin() (gas: 14965) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVerifier() (gas: 12697) VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17965) -VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 198408) -VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 116307) +VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 198420) +VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 116319) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 538582) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 964048) VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 520140) @@ -227,10 +237,10 @@ VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesDigestsOnM VerifierSetConfigWhenThereAreMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 519921) VerifierSupportsInterfaceTest:test_falseIfIsNotCorrectInterface() (gas: 5590) VerifierSupportsInterfaceTest:test_trueIfIsCorrectInterface() (gas: 5633) -VerifierTestBillingReport:test_verifyWithLink() (gas: 280557) -VerifierTestBillingReport:test_verifyWithNative() (gas: 321248) -VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 323491) -VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 330557) +VerifierTestBillingReport:test_verifyWithLink() (gas: 278542) +VerifierTestBillingReport:test_verifyWithNative() (gas: 319232) +VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 321475) +VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 328541) VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 131228) VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 187132) VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88205) @@ -245,11 +255,11 @@ VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 10 VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184066) VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110031) VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194270) -Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 208841) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 542038) -Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 565410) +Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 208853) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 540669) +Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 564041) Verifier_setConfig:testSetConfigSuccess_gas() (gas: 922428) -Verifier_verify:testVerifyProxySuccess_gas() (gas: 195530) +Verifier_verify:testVerifyProxySuccess_gas() (gas: 195542) Verifier_verify:testVerifySuccess_gas() (gas: 186725) -Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 244506) -Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 262984) \ No newline at end of file +Verifier_verifyWithFee:testVerifyProxyWithLinkFeeSuccess_gas() (gas: 242491) +Verifier_verifyWithFee:testVerifyProxyWithNativeFeeSuccess_gas() (gas: 260968) \ No newline at end of file diff --git a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol index be2f411c0e9..4df6691b6ac 100644 --- a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/VerifierProxy.sol @@ -7,7 +7,7 @@ import {IVerifier} from "./interfaces/IVerifier.sol"; import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol"; import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol"; import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; -import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./dev/interfaces/IVerifierFeeManager.sol"; import {Common} from "../libraries/Common.sol"; /** @@ -65,6 +65,10 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac /// not conform to the verifier interface error VerifierInvalid(); + /// @notice This error is thrown when the fee manager at an address does + /// not conform to the fee manager interface + error FeeManagerInvalid(); + /// @notice This error is thrown whenever a verifier is not found /// @param configDigest The digest for which a verifier is not found error VerifierNotFound(bytes32 configDigest); @@ -117,7 +121,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IVerifierProxy - function verify(bytes calldata payload) external payable checkAccess returns (bytes memory verifiedReport) { + function verify(bytes calldata payload) external payable checkAccess returns (bytes memory) { IVerifierFeeManager feeManager = s_feeManager; // Bill the verifier @@ -192,7 +196,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IVerifierProxy - function getVerifier(bytes32 configDigest) external view override returns (address verifierAddress) { + function getVerifier(bytes32 configDigest) external view override returns (address) { return s_verifiersByConfig[configDigest]; } @@ -207,6 +211,11 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac function setFeeManager(IVerifierFeeManager feeManager) external onlyOwner { if (address(feeManager) == address(0)) revert ZeroAddress(); + if ( + !IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFee.selector) || + !IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFeeBulk.selector) + ) revert FeeManagerInvalid(); + address oldFeeManager = address(s_feeManager); s_feeManager = IVerifierFeeManager(feeManager); emit FeeManagerSet(oldFeeManager, address(feeManager)); diff --git a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol index 341ac19762e..2e5d060dca6 100644 --- a/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/FeeManager.sol @@ -11,6 +11,7 @@ import {IWERC20} from "../../shared/interfaces/IWERC20.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol"; import {Math} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol"; import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol"; /** * @title FeeManager @@ -75,6 +76,9 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { // @notice thrown when trying to clear a zero deficit error ZeroDeficit(); + /// @notice thrown when trying to pay an address that cannot except funds + error InvalidReceivingAddress(); + /// @notice Emitted whenever a subscriber's discount is updated /// @param subscriber address of the subscriber to update discounts for /// @param feedId Feed ID for the discount @@ -91,15 +95,31 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { event InsufficientLink(IRewardManager.FeePayment[] rewards); /// @notice Emitted when funds are withdrawn + /// @param adminAddress Address of the admin + /// @param recipient Address of the recipient /// @param assetAddress Address of the asset withdrawn /// @param quantity Amount of the asset withdrawn - event Withdraw(address adminAddress, address assetAddress, uint192 quantity); + event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity); /// @notice Emits when a deficit has been cleared for a particular config digest /// @param configDigest Config digest of the deficit cleared /// @param linkQuantity Amount of LINK required to pay the deficit event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity); + /// @notice Emits when a fee has been processed + /// @param configDigest Config digest of the fee processed + /// @param subscriber Address of the subscriber who paid the fee + /// @param fee Fee paid + /// @param reward Reward paid + /// @param appliedDiscount Discount applied to the fee + event DiscountApplied( + bytes32 indexed configDigest, + address indexed subscriber, + Common.Asset fee, + Common.Asset reward, + uint256 appliedDiscount + ); + /** * @notice Construct the FeeManager contract * @param _linkAddress The address of the LINK token @@ -133,9 +153,14 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { _; } + modifier onlyProxy() { + if (msg.sender != i_proxyAddress) revert Unauthorized(); + _; + } + /// @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure override returns (string memory) { - return "FeeManager 0.0.1"; + return "FeeManager 1.0.0"; } /// @inheritdoc IERC165 @@ -143,9 +168,9 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { return interfaceId == this.processFee.selector || interfaceId == this.processFeeBulk.selector; } - /// @inheritdoc IFeeManager - function processFee(bytes calldata payload, address subscriber) external payable override onlyOwnerOrProxy { - (Common.Asset memory fee, Common.Asset memory reward) = _processFee(payload, subscriber); + /// @inheritdoc IVerifierFeeManager + function processFee(bytes calldata payload, address subscriber) external payable override onlyProxy { + (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(payload, subscriber); if (fee.amount == 0) { _tryReturnChange(subscriber, msg.value); @@ -153,7 +178,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } IFeeManager.FeeAndReward[] memory feeAndReward = new IFeeManager.FeeAndReward[](1); - feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward); + feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward, appliedDiscount); if (fee.assetAddress == i_linkAddress) { _handleFeesAndRewards(subscriber, feeAndReward, 1, 0); @@ -162,8 +187,8 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } } - /// @inheritdoc IFeeManager - function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyOwnerOrProxy { + /// @inheritdoc IVerifierFeeManager + function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyProxy { FeeAndReward[] memory feesAndRewards = new IFeeManager.FeeAndReward[](payloads.length); //keep track of the number of fees to prevent over initialising the FeePayment array within _convertToLinkAndNativeFees @@ -172,10 +197,18 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { uint256 feesAndRewardsIndex; for (uint256 i; i < payloads.length; ++i) { - (Common.Asset memory fee, Common.Asset memory reward) = _processFee(payloads[i], subscriber); + (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee( + payloads[i], + subscriber + ); if (fee.amount != 0) { - feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(bytes32(payloads[i]), fee, reward); + feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward( + bytes32(payloads[i]), + fee, + reward, + appliedDiscount + ); unchecked { //keep track of some tallys to make downstream calculations more efficient @@ -200,7 +233,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { address subscriber, bytes memory report, Quote memory quote - ) public view returns (Common.Asset memory, Common.Asset memory) { + ) public view returns (Common.Asset memory, Common.Asset memory, uint256) { Common.Asset memory fee; Common.Asset memory reward; @@ -214,7 +247,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { if (reportVersion == REPORT_V1) { fee.assetAddress = i_nativeAddress; reward.assetAddress = i_linkAddress; - return (fee, reward); + return (fee, reward, 0); } //verify the quote payload is a supported token @@ -255,10 +288,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } //return the fee - return (fee, reward); + return (fee, reward, discount); } - /// @inheritdoc IFeeManager + /// @inheritdoc IVerifierFeeManager function setFeeRecipients( bytes32 configDigest, Common.AddressAndWeight[] calldata rewardRecipientAndWeights @@ -293,18 +326,20 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { } /// @inheritdoc IFeeManager - function withdraw(address assetAddress, uint192 quantity) external onlyOwner { + function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner { //address 0 is used to withdraw native in the context of withdrawing if (assetAddress == address(0)) { - payable(owner()).transfer(quantity); + (bool success, ) = payable(recipient).call{value: quantity}(""); + + if (!success) revert InvalidReceivingAddress(); return; } //withdraw the requested asset - IERC20(assetAddress).safeTransfer(owner(), quantity); + IERC20(assetAddress).safeTransfer(recipient, quantity); //emit event when funds are withdrawn - emit Withdraw(msg.sender, assetAddress, quantity); + emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity)); } /// @inheritdoc IFeeManager @@ -324,7 +359,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { function _processFee( bytes calldata payload, address subscriber - ) internal view returns (Common.Asset memory, Common.Asset memory) { + ) internal view returns (Common.Asset memory, Common.Asset memory, uint256) { if (subscriber == address(this)) revert InvalidAddress(); //decode the report from the payload @@ -381,6 +416,16 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { totalNativeFee += feesAndRewards[i].fee.amount; totalNativeFeeLinkValue += feesAndRewards[i].reward.amount; } + + if (feesAndRewards[i].appliedDiscount != 0) { + emit DiscountApplied( + feesAndRewards[i].configDigest, + subscriber, + feesAndRewards[i].fee, + feesAndRewards[i].reward, + feesAndRewards[i].appliedDiscount + ); + } } //keep track of change in case of any over payment @@ -390,7 +435,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { //there must be enough to cover the fee if (totalNativeFee > msg.value) revert InvalidDeposit(); - //wrap the amount required to pay the fee & approve as the subscriber paid in unwrapped native + //wrap the amount required to pay the fee & approve as the subscriber paid in wrapped native IWERC20(i_nativeAddress).deposit{value: totalNativeFee}(); unchecked { @@ -413,7 +458,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface { if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) { // If not enough LINK on this contract to forward for rewards, tally the deficit to be paid by out-of-band LINK for (uint256 i; i < nativeFeeLinkRewards.length; ++i) { - s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount; + unchecked { + //we have previously tallied the fees, any overflows would have already reverted + s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount; + } } emit InsufficientLink(nativeFeeLinkRewards); diff --git a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol index 8858f82c958..3f7e524c02b 100644 --- a/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/RewardManager.sol @@ -54,11 +54,14 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac // @notice Thrown when the calling contract is not within the authorized contracts error Unauthorized(); + // @notice Thrown when getAvailableRewardPoolIds parameters are incorrectly set + error InvalidPoolLength(); + // Events emitted upon state change event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients); event RewardsClaimed(bytes32 indexed poolId, address indexed recipient, uint192 quantity); event FeeManagerUpdated(address newFeeManagerAddress); - event FeePaid(FeePayment[] payments, address payee); + event FeePaid(FeePayment[] payments, address payer); /** * @notice Constructor @@ -73,7 +76,7 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac // @inheritdoc TypeAndVersionInterface function typeAndVersion() external pure override returns (string memory) { - return "RewardManager 0.0.1"; + return "RewardManager 1.0.0"; } // @inheritdoc IERC165 @@ -91,8 +94,13 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac _; } + modifier onlyFeeManager() { + if (msg.sender != s_feeManagerAddress) revert Unauthorized(); + _; + } + /// @inheritdoc IRewardManager - function onFeePaid(FeePayment[] calldata payments, address payee) external override onlyOwnerOrFeeManager { + function onFeePaid(FeePayment[] calldata payments, address payer) external override onlyFeeManager { uint256 totalFeeAmount; for (uint256 i; i < payments.length; ++i) { unchecked { @@ -105,9 +113,9 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac } //transfer the fees to this contract - IERC20(i_linkAddress).safeTransferFrom(payee, address(this), totalFeeAmount); + IERC20(i_linkAddress).safeTransferFrom(payer, address(this), totalFeeAmount); - emit FeePaid(payments, payee); + emit FeePaid(payments, payer); } /// @inheritdoc IRewardManager @@ -276,19 +284,28 @@ contract RewardManager is IRewardManager, ConfirmedOwner, TypeAndVersionInterfac } /// @inheritdoc IRewardManager - function getAvailableRewardPoolIds(address recipient) external view returns (bytes32[] memory) { + function getAvailableRewardPoolIds( + address recipient, + uint256 startIndex, + uint256 endIndex + ) external view returns (bytes32[] memory) { //get the length of the pool ids which we will loop through and potentially return uint256 registeredPoolIdsLength = s_registeredPoolIds.length; + uint256 lastIndex = endIndex > registeredPoolIdsLength ? registeredPoolIdsLength : endIndex; + + if (startIndex > lastIndex) revert InvalidPoolLength(); + //create a new array with the maximum amount of potential pool ids - bytes32[] memory claimablePoolIds = new bytes32[](registeredPoolIdsLength); + bytes32[] memory claimablePoolIds = new bytes32[](lastIndex - startIndex); //we want the pools which a recipient has funds for to be sequential, so we need to keep track of the index uint256 poolIdArrayIndex; //loop all the pool ids, and check if the recipient has a registered weight and a claimable amount - for (uint256 i; i < registeredPoolIdsLength; ++i) { + for (uint256 i = startIndex; i < lastIndex; ++i) { //get the poolId bytes32 poolId = s_registeredPoolIds[i]; + //if the recipient has a weight, they are a recipient of this poolId if (s_rewardRecipientWeights[poolId][recipient] != 0) { //get the total in this pool diff --git a/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol index ff81aafe5d3..49fd7f95587 100644 --- a/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IFeeManager.sol @@ -3,49 +3,21 @@ pragma solidity 0.8.16; import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; import {Common} from "../../../libraries/Common.sol"; -import {IVerifierFeeManager} from "../../interfaces/IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; interface IFeeManager is IERC165, IVerifierFeeManager { - struct Quote { - address quoteAddress; - } - - /** - * @notice Processes the fee for a report, billing the subscriber and paying the reward manager - * @param payload report and quote data to process the fee for - * @param subscriber address of the user to process fee for - */ - function processFee(bytes calldata payload, address subscriber) external payable; - - /** - * @notice Processes the fees for each report in the payload, billing the subscriber and paying the reward manager - * @param payloads reports and quotes to process - * @param subscriber address of the user to process fee for - */ - function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable; - /** * @notice Calculate the applied fee and the reward from a report. If the sender is a subscriber, they will receive a discount. * @param subscriber address trying to verify * @param report report to calculate the fee for * @param quote any metadata required to fetch the fee - * @return (fee, reward) fee and the reward data + * @return (fee, reward, totalDiscount) fee and the reward data with the discount applied */ function getFeeAndReward( address subscriber, bytes memory report, Quote memory quote - ) external returns (Common.Asset memory, Common.Asset memory); - - /** - * @notice Sets the fee recipients within the reward manager - * @param configDigest digest of the configuration - * @param rewardRecipientAndWeights the address and weights of all the recipients to receive rewards - */ - function setFeeRecipients( - bytes32 configDigest, - Common.AddressAndWeight[] calldata rewardRecipientAndWeights - ) external; + ) external returns (Common.Asset memory, Common.Asset memory, uint256); /** * @notice Sets the native surcharge @@ -64,10 +36,11 @@ interface IFeeManager is IERC165, IVerifierFeeManager { /** * @notice Withdraws any native or LINK rewards to the owner address - * @param quantity quantity of tokens to withdraw, address(0) is native + * @param assetAddress address of the asset to withdraw + * @param recipientAddress address to withdraw to * @param quantity quantity to withdraw */ - function withdraw(address assetAddress, uint192 quantity) external; + function withdraw(address assetAddress, address recipientAddress, uint192 quantity) external; /** * @notice Returns the link balance of the fee manager @@ -86,10 +59,20 @@ interface IFeeManager is IERC165, IVerifierFeeManager { * @param digest the digest linked to the fee and reward * @param fee the fee paid to verify the report * @param reward the reward paid upon verification + & @param appliedDiscount the discount applied to the reward */ struct FeeAndReward { bytes32 configDigest; Common.Asset fee; Common.Asset reward; + uint256 appliedDiscount; + } + + /** + * @notice The structure to hold quote metadata + * @param quoteAddress the address of the quote + */ + struct Quote { + address quoteAddress; } } diff --git a/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol index e9b351c935c..8f6b1921e94 100644 --- a/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IRewardManager.sol @@ -48,8 +48,14 @@ interface IRewardManager is IERC165 { /** * @notice Gets a list of pool ids which have reward for a specific recipient. * @param recipient address of the recipient to get pool ids for + * @param startIndex the index to start from + * @param endIndex the index to stop at */ - function getAvailableRewardPoolIds(address recipient) external view returns (bytes32[] memory); + function getAvailableRewardPoolIds( + address recipient, + uint256 startIndex, + uint256 endIndex + ) external view returns (bytes32[] memory); /** * @notice The structure to hold a fee payment notice diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol b/contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol similarity index 87% rename from contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol rename to contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol index 92220582ba4..c9b1a821746 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol +++ b/contracts/src/v0.8/llo-feeds/dev/interfaces/IVerifierFeeManager.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; -import {Common} from "../../libraries/Common.sol"; +import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol"; +import {Common} from "../../../libraries/Common.sol"; interface IVerifierFeeManager is IERC165 { /** diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol index be221263c56..82ac492f5c3 100644 --- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol +++ b/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.16; import {Common} from "../../libraries/Common.sol"; import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol"; -import {IVerifierFeeManager} from "./IVerifierFeeManager.sol"; +import {IVerifierFeeManager} from "./../dev/interfaces/IVerifierFeeManager.sol"; interface IVerifierProxy { /** diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol index 10bd89331f1..6b8858fc93f 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol @@ -75,8 +75,15 @@ contract BaseFeeManagerTest is Test { event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount); event NativeSurchargeUpdated(uint64 newSurcharge); event InsufficientLink(IRewardManager.FeePayment[] feesAndRewards); - event Withdraw(address adminAddress, address assetAddress, uint192 quantity); + event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity); event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity); + event DiscountApplied( + bytes32 indexed configDigest, + address indexed subscriber, + Common.Asset fee, + Common.Asset reward, + uint256 appliedDiscountQuantity + ); function setUp() public virtual { //change to admin user @@ -153,7 +160,7 @@ contract BaseFeeManagerTest is Test { address subscriber ) public view returns (Common.Asset memory) { //get the fee - (Common.Asset memory fee, ) = feeManager.getFeeAndReward(subscriber, report, quote); + (Common.Asset memory fee, , ) = feeManager.getFeeAndReward(subscriber, report, quote); return fee; } @@ -164,11 +171,22 @@ contract BaseFeeManagerTest is Test { address subscriber ) public view returns (Common.Asset memory) { //get the reward - (, Common.Asset memory reward) = feeManager.getFeeAndReward(subscriber, report, quote); + (, Common.Asset memory reward, ) = feeManager.getFeeAndReward(subscriber, report, quote); return reward; } + function getAppliedDiscount( + bytes memory report, + IFeeManager.Quote memory quote, + address subscriber + ) public view returns (uint256) { + //get the reward + (, , uint256 appliedDiscount) = feeManager.getFeeAndReward(subscriber, report, quote); + + return appliedDiscount; + } + function getV1Report(bytes32 feedId) public pure returns (bytes memory) { return abi.encode(feedId, uint32(0), int192(0), int192(0), int192(0), uint64(0), bytes32(0), uint64(0), uint64(0)); } @@ -229,13 +247,13 @@ contract BaseFeeManagerTest is Test { return IFeeManager.Quote(getNativeAddress()); } - function withdraw(address assetAddress, uint256 amount, address sender) public { + function withdraw(address assetAddress, address recipient, uint256 amount, address sender) public { //record the current address and switch to the recipient address originalAddr = msg.sender; changePrank(sender); //set the surcharge - feeManager.withdraw(assetAddress, uint192(amount)); + feeManager.withdraw(assetAddress, recipient, uint192(amount)); //change back to the original address changePrank(originalAddr); diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol index 2e5d6cf15e7..d776c54eb36 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol @@ -28,7 +28,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { uint256 withdrawAmount = contractBalance / 2; //withdraw some balance - withdraw(getLinkAddress(), withdrawAmount, ADMIN); + withdraw(getLinkAddress(), ADMIN, withdrawAmount, ADMIN); //check the balance has been reduced uint256 newContractBalance = getLinkBalance(address(feeManager)); @@ -54,7 +54,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { uint256 withdrawAmount = contractBalance / 2; //withdraw some balance - withdraw(NATIVE_WITHDRAW_ADDRESS, withdrawAmount, ADMIN); + withdraw(NATIVE_WITHDRAW_ADDRESS, ADMIN, withdrawAmount, ADMIN); //check the balance has been reduced uint256 newContractBalance = getNativeUnwrappedBalance(address(feeManager)); @@ -76,7 +76,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR); //withdraw some balance - withdraw(getLinkAddress(), DEFAULT_LINK_MINT_QUANTITY, USER); + withdraw(getLinkAddress(), ADMIN, DEFAULT_LINK_MINT_QUANTITY, USER); } function test_eventIsEmittedAfterSurchargeIsSet() public { @@ -118,10 +118,10 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { vm.expectEmit(); //the event to be emitted - emit Withdraw(ADMIN, getLinkAddress(), withdrawAmount); + emit Withdraw(ADMIN, ADMIN, getLinkAddress(), withdrawAmount); //withdraw some balance - withdraw(getLinkAddress(), withdrawAmount, ADMIN); + withdraw(getLinkAddress(), ADMIN, withdrawAmount, ADMIN); } function test_linkAvailableForPaymentReturnsLinkBalance() public { diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol index d59ced1a237..f31c06bd41e 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol @@ -570,4 +570,40 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { USER ); } + + function test_discountIsReturnedForLink() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getLinkAddress(), FEE_SCALAR / 2, ADMIN); + + //get the fee applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } + + function test_DiscountIsReturnedForNative() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //get the discount applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } + + function test_DiscountIsReturnedForNativeWithSurcharge() public { + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //set the surcharge + setNativeSurcharge(FEE_SCALAR / 5, ADMIN); + + //get the discount applied + uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + //fee should be half the default + assertEq(discount, FEE_SCALAR / 2); + } } diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol index ab13a60c371..aa0ca063d85 100644 --- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol @@ -455,4 +455,46 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest { //check the unused native passed in is returned assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY); } + + function test_processFeeWithDiscountEmitsEvent() public { + //simulate a deposit of link for the conversion pool + mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE); + + //set the subscriber discount to 50% + setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, getNativeAddress(), FEE_SCALAR / 2, ADMIN); + + //approve the native to be transferred from the user + approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE / 2, USER); + + //get the default payload + bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3), getQuotePayload(getNativeAddress())); + + Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + uint256 appliedDiscount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER); + + vm.expectEmit(); + + emit DiscountApplied(DEFAULT_CONFIG_DIGEST, USER, fee, reward, appliedDiscount); + + //call processFee should not revert as the fee is 0 + processFee(payload, USER, 0); + } + + function test_processFeeWithNoDiscountDoesNotEmitEvent() public { + //simulate a deposit of link for the conversion pool + mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE); + + //approve the native to be transferred from the user + approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER); + + //get the default payload + bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3), getQuotePayload(getNativeAddress())); + + //call processFee should not revert as the fee is 0 + processFee(payload, USER, 0); + + //no logs should have been emitted + assertEq(vm.getRecordedLogs().length, 0); + } } diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol index a54431b64a2..a82859df624 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol @@ -67,6 +67,7 @@ contract BaseRewardManagerTest is Test { bytes4 internal immutable INVALID_WEIGHT_ERROR_SELECTOR = RewardManager.InvalidWeights.selector; bytes4 internal immutable INVALID_POOL_ID_ERROR_SELECTOR = RewardManager.InvalidPoolId.selector; bytes internal constant ONLY_CALLABLE_BY_OWNER_ERROR = "Only callable by owner"; + bytes4 internal immutable INVALID_POOL_LENGTH_SELECTOR = RewardManager.InvalidPoolLength.selector; // Events emitted within the reward manager event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients); diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol index db514c5dd8a..9a3749d1dde 100644 --- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol @@ -550,7 +550,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInBothPools() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[0].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -559,7 +563,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInSinglePool() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[1].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[1].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -568,7 +576,7 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInNoPools() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, 0, type(uint256).max); //check the recipient is in neither pool assertEq(poolIds[0], ZERO_POOL_ID); @@ -577,7 +585,11 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { function test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() public { //get index 0 as this recipient is in both default pools - bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds( + getPrimaryRecipients()[0].addr, + 0, + type(uint256).max + ); //check the recipient is in both pools assertEq(poolIds[0], PRIMARY_POOL_ID); @@ -588,12 +600,30 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest { claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr); //get the available pools again - poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr); + poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, type(uint256).max); //user should not be in any pool assertEq(poolIds[0], ZERO_POOL_ID); assertEq(poolIds[1], ZERO_POOL_ID); } + + function test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() public { + vm.expectRevert(INVALID_POOL_LENGTH_SELECTOR); + + rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, type(uint256).max, 0); + } + + function test_getAvailableRewardsCursorAndTotalPoolsEqual() public { + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 2, 2); + + assertEq(poolIds.length, 0); + } + + function test_getAvailableRewardsCursorSingleResult() public { + bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, 1); + + assertEq(poolIds[0], PRIMARY_POOL_ID); + } } contract RewardManagerRecipientClaimDifferentWeightsTest is BaseRewardManagerTest { diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol index 4d1c57cd822..0aae95b3da2 100644 --- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol +++ b/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol @@ -14,4 +14,14 @@ contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAn vm.expectRevert(abi.encodeWithSelector(VerifierProxy.ZeroAddress.selector)); s_verifierProxy.setFeeManager(FeeManager(address(0))); } + + function test_setFeeManagerWhichDoesntHonourInterface() public { + vm.expectRevert(abi.encodeWithSelector(VerifierProxy.FeeManagerInvalid.selector)); + s_verifierProxy.setFeeManager(FeeManager(address(s_verifier))); + } + + function test_setFeeManagerWhichDoesntHonourIERC165Interface() public { + vm.expectRevert(); + s_verifierProxy.setFeeManager(FeeManager(address(1))); + } } diff --git a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go index 75fcba1ce41..d8fdd50e6ed 100644 --- a/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go +++ b/core/gethwrappers/llo-feeds/generated/fee_manager/fee_manager.go @@ -50,8 +50,8 @@ type IRewardManagerFeePayment struct { } var FeeManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x6101006040523480156200001257600080fd5b50604051620033c1380380620033c1833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051612feb620003d6600039600081816111250152818161146e01528181611b770152611dd201526000818161059f015281816111e501526113b4015260008181610a2101528181610a7401528181610d2b01528181610e3701528181611a9d0152611b4601526000818161073301528181610a4601528181610acf01528181610c1901528181610c8801528181610cc701528181610de001528181610f770152818161130a015281816118460152611c380152612feb6000f3fe60806040526004361061010e5760003560e01c806387d6d843116100a5578063d09dc33911610074578063f1387e1611610059578063f1387e1614610345578063f2fde38b14610358578063f65df9621461037857600080fd5b8063d09dc33914610310578063e389d9a41461032557600080fd5b806387d6d8431461024f5780638da5cb5b1461028d578063c541cbde146102c2578063ce7817d1146102f057600080fd5b806332f5f746116100e157806332f5f746146101f157806340d7f78e14610207578063505380941461021a57806379ba50971461023a57600080fd5b8063013f542b1461011357806301ffc9a7146101535780631791dc5e14610183578063181f5a77146101a5575b600080fd5b34801561011f57600080fd5b5061014061012e3660046123ce565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561015f57600080fd5b5061017361016e3660046123e7565b610398565b604051901515815260200161014a565b34801561018f57600080fd5b506101a361019e366004612471565b610431565b005b3480156101b157600080fd5b50604080518082018252601081527f4665654d616e6167657220302e302e31000000000000000000000000000000006020820152905161014a91906124ce565b3480156101fd57600080fd5b5061014060045481565b6101a361021536600461251f565b610587565b34801561022657600080fd5b506101a36102353660046125c2565b6107e4565b34801561024657600080fd5b506101a361087e565b34801561025b57600080fd5b5061014061026a3660046125dd565b600260209081526000938452604080852082529284528284209052825290205481565b34801561029957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b3480156102ce57600080fd5b506102e26102dd366004612749565b610980565b60405161014a9291906127ea565b3480156102fc57600080fd5b506101a361030b36600461283e565b610d8a565b34801561031c57600080fd5b50610140610f46565b34801561033157600080fd5b506101a36103403660046123ce565b610ffc565b6101a361035336600461288f565b6111cd565b34801561036457600080fd5b506101a36103733660046128f1565b611388565b34801561038457600080fd5b506101a361039336600461290e565b61139c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e1600000000000000000000000000000000000000000000000000000000148061042b57507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b6104396114d5565b73ffffffffffffffffffffffffffffffffffffffff82166104ba576000805460405173ffffffffffffffffffffffffffffffffffffffff9091169177ffffffffffffffffffffffffffffffffffffffffffffffff841680156108fc02929091818181858888f193505050501580156104b5573d6000803e3d6000fd5b505050565b6105146104dc60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff84169077ffffffffffffffffffffffffffffffffffffffffffffffff8416611558565b6040805133815273ffffffffffffffffffffffffffffffffffffffff8416602082015277ffffffffffffffffffffffffffffffffffffffffffffffff83168183015290517f72608e45b52a95a12c2ac7f15ff53f92fc9572c9d84b6e6b5d7f0f7826cf32719181900360600190a15b5050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906105e5575060005473ffffffffffffffffffffffffffffffffffffffff163314155b1561061c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff81111561063757610637612614565b60405190808252806020026020018201604052801561067057816020015b61065d612349565b8152602001906001900390816106555790505b5090506000806000805b868110156107ad576000806106b28a8a8581811061069a5761069a61298d565b90506020028101906106ac91906129bc565b8a61162c565b91509150816020015160001461079a5760405180606001604052808b8b868181106106df576106df61298d565b90506020028101906106f191906129bc565b6106fa91612a28565b815260208101849052604001829052878561071481612a93565b9650815181106107265761072661298d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16036107935785600101955061079a565b8460010194505b5050806107a690612a93565b905061067a565b50821515806107bb57508115155b156107d1576107cc85858585611761565b6107db565b6107db8534611e54565b50505050505050565b6107ec6114d5565b670de0b6b3a764000067ffffffffffffffff82161115610838576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610904576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b604080518082019091526000808252602082015260408051808201909152600080825260208201526040805180820190915260008082526020820152604080518082019091526000808252602082015260006109db87612acb565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610a7257505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f00000000000000000000000000000000000000000000000000000000000000001681529092509050610d82565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff1614158015610b2257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610b59576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008a806020019051810190610b729190612b24565b77ffffffffffffffffffffffffffffffffffffffffffffffff92831698509116955063ffffffff1693505050428210159050610bda576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808d16600090815260026020908152604080832089845282528083208e51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610c6a610c5282670de0b6b3a7640000612b96565b610c5c9086612ba9565b670de0b6b3a7640000611e9d565b60208801528a5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610cf85773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610d75565b600454600090610d1490610c5290670de0b6b3a7640000612be6565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610d6e610d6483670de0b6b3a7640000612b96565b610c5c9083612ba9565b60208a0152505b5095975093955050505050505b935093915050565b610d926114d5565b670de0b6b3a764000067ffffffffffffffff82161115610dde576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610e8657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610ebd576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610fd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff79190612bf9565b905090565b6110046114d5565b6000818152600360205260408120549081900361104d576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b604080518082019091526000808252602082015281526020019060019003908161107257905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff16815250816000815181106110dd576110dd61298d565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa199061115c9084903090600401612c72565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd9895836040516111c091815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480159061122b575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611262576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061127085858561162c565b9150915081602001516000036112915761128a8334611e54565b5050505050565b604080516001808252818301909252600091816020015b6112b0612349565b8152602001906001900390816112a85750506040805160608101909152909150806112db8789612a28565b815260200184815260200183815250816000815181106112fd576112fd61298d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036113725761136d848260016000611761565b611380565b611380848260006001611761565b505050505050565b6113906114d5565b61139981611ed5565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906113fa575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611431576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f23906114a790869086908690600401612caa565b600060405180830381600087803b1580156114c157600080fd5b505af11580156107db573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff163314611556576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108fb565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526104b59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611fca565b604080518082019091526000808252602082015260408051808201909152600080825260208201523073ffffffffffffffffffffffffffffffffffffffff8416036116a3576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116b185870187612d98565b9150506000816116c090612acb565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611747576000611728888a018a612e5c565b95505050505050808060200190518101906117439190612f24565b9150505b611752868483610980565b94509450505050935093915050565b60008267ffffffffffffffff81111561177c5761177c612614565b6040519080825280602002602001820160405280156117c157816020015b604080518082019091526000808252602082015281526020019060019003908161179a5790505b50905060008267ffffffffffffffff8111156117df576117df612614565b60405190808252806020026020018201604052801561182457816020015b60408051808201909152600080825260208201528152602001906001900390816117fd5790505b509050600080808080611837888a612be6565b905060005b81811015611a58577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b828151811061188d5761188d61298d565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036119535760405180604001604052808c83815181106118d5576118d561298d565b60200260200101516000015181526020018c83815181106118f8576118f861298d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525088858061193190612a93565b9650815181106119435761194361298d565b6020026020010181905250611a48565b60405180604001604052808c83815181106119705761197061298d565b60200260200101516000015181526020018c83815181106119935761199361298d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff168152508784806119cc90612a93565b9550815181106119de576119de61298d565b60200260200101819052508a81815181106119fb576119fb61298d565b6020026020010151602001516020015186611a169190612be6565b95508a8181518110611a2a57611a2a61298d565b6020026020010151604001516020015185611a459190612be6565b94505b611a5181612a93565b905061183c565b5060003415611b265734861115611a9b576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0357600080fd5b505af1158015611b17573d6000803e3d6000fd5b50505050508534039050611b6e565b8515611b6e57611b6e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d30896120d6565b875115611c03577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611bd0929190612c72565b600060405180830381600087803b158015611bea57600080fd5b505af1158015611bfe573d6000803e3d6000fd5b505050505b865115611e3c576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611c94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb89190612bf9565b851115611d955760005b8751811015611d5857878181518110611cdd57611cdd61298d565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611d1957611d1961298d565b60200260200101516000015181526020019081526020016000206000828254611d429190612be6565b90915550611d51905081612a93565b9050611cc2565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b6787604051611d889190612f52565b60405180910390a1611e3c565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990611e09908a903090600401612c72565b600060405180830381600087803b158015611e2357600080fd5b505af1158015611e37573d6000803e3d6000fd5b505050505b611e468c82611e54565b505050505050505050505050565b80156105835760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156104b5573d6000803e3d6000fd5b60008215611ecb5781611eb1600185612b96565b611ebb9190612f65565b611ec6906001612be6565b611ece565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611f54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061202c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661213a9092919063ffffffff16565b8051909150156104b5578080602001905181019061204a9190612fa0565b6104b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108fb565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526121349085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115aa565b50505050565b60606121498484600085612151565b949350505050565b6060824710156121e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108fb565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161220c9190612fc2565b60006040518083038185875af1925050503d8060008114612249576040519150601f19603f3d011682016040523d82523d6000602084013e61224e565b606091505b509150915061225f8783838761226a565b979650505050505050565b606083156123005782516000036122f95773ffffffffffffffffffffffffffffffffffffffff85163b6122f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108fb565b5081612149565b61214983838151156123155781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108fb91906124ce565b6040518060600160405280600080191681526020016123916040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b81526020016123c96040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b905290565b6000602082840312156123e057600080fd5b5035919050565b6000602082840312156123f957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611ece57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461139957600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff8116811461139957600080fd5b6000806040838503121561248457600080fd5b823561248f81612429565b9150602083013561249f8161244b565b809150509250929050565b60005b838110156124c55781810151838201526020016124ad565b50506000910152565b60208152600082518060208401526124ed8160408501602087016124aa565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60008060006040848603121561253457600080fd5b833567ffffffffffffffff8082111561254c57600080fd5b818601915086601f83011261256057600080fd5b81358181111561256f57600080fd5b8760208260051b850101111561258457600080fd5b6020928301955093505084013561259a81612429565b809150509250925092565b803567ffffffffffffffff811681146125bd57600080fd5b919050565b6000602082840312156125d457600080fd5b611ece826125a5565b6000806000606084860312156125f257600080fd5b83356125fd81612429565b925060208401359150604084013561259a81612429565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff8111828210171561266657612666612614565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126b3576126b3612614565b604052919050565b600082601f8301126126cc57600080fd5b813567ffffffffffffffff8111156126e6576126e6612614565b61271760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161266c565b81815284602083860101111561272c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000838503606081121561275f57600080fd5b843561276a81612429565b9350602085013567ffffffffffffffff81111561278657600080fd5b612792878288016126bb565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0820112156127c557600080fd5b506127ce612643565b60408501356127dc81612429565b815292959194509192509050565b825173ffffffffffffffffffffffffffffffffffffffff1681526020808401519082015260808101825173ffffffffffffffffffffffffffffffffffffffff16604083015260208301516060830152611ece565b6000806000806080858703121561285457600080fd5b843561285f81612429565b935060208501359250604085013561287681612429565b9150612884606086016125a5565b905092959194509250565b6000806000604084860312156128a457600080fd5b833567ffffffffffffffff808211156128bc57600080fd5b818601915086601f8301126128d057600080fd5b8135818111156128df57600080fd5b87602082850101111561258457600080fd5b60006020828403121561290357600080fd5b8135611ece81612429565b60008060006040848603121561292357600080fd5b83359250602084013567ffffffffffffffff8082111561294257600080fd5b818601915086601f83011261295657600080fd5b81358181111561296557600080fd5b8760208260061b850101111561297a57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126129f157600080fd5b83018035915067ffffffffffffffff821115612a0c57600080fd5b602001915036819003821315612a2157600080fd5b9250929050565b8035602083101561042b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612ac457612ac4612a64565b5060010190565b80516020808301519190811015612b0a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff811681146125bd57600080fd5b60008060008060008060c08789031215612b3d57600080fd5b86519550612b4d60208801612b10565b9450612b5b60408801612b10565b93506060870151612b6b8161244b565b6080880151909350612b7c8161244b565b9150612b8a60a08801612b10565b90509295509295509295565b8181038181111561042b5761042b612a64565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612be157612be1612a64565b500290565b8082018082111561042b5761042b612a64565b600060208284031215612c0b57600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612c675781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612c26565b509495945050505050565b604081526000612c856040830185612c12565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612d1d578335612cdc81612429565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612d088585016125a5565b16828401529284019290840190600101612cc9565b5098975050505050505050565b600082601f830112612d3b57600080fd5b6040516060810181811067ffffffffffffffff82111715612d5e57612d5e612614565b604052806060840185811115612d7357600080fd5b845b81811015612d8d578035835260209283019201612d75565b509195945050505050565b60008060808385031215612dab57600080fd5b612db58484612d2a565b9150606083013567ffffffffffffffff811115612dd157600080fd5b612ddd858286016126bb565b9150509250929050565b600082601f830112612df857600080fd5b8135602067ffffffffffffffff821115612e1457612e14612614565b8160051b612e2382820161266c565b9283528481018201928281019087851115612e3d57600080fd5b83870192505b8483101561225f57823582529183019190830190612e43565b6000806000806000806101008789031215612e7657600080fd5b612e808888612d2a565b9550606087013567ffffffffffffffff80821115612e9d57600080fd5b612ea98a838b016126bb565b96506080890135915080821115612ebf57600080fd5b612ecb8a838b01612de7565b955060a0890135915080821115612ee157600080fd5b612eed8a838b01612de7565b945060c0890135935060e0890135915080821115612f0a57600080fd5b50612f1789828a016126bb565b9150509295509295509295565b600060208284031215612f3657600080fd5b612f3e612643565b8251612f4981612429565b81529392505050565b602081526000611ece6020830184612c12565b600082612f9b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600060208284031215612fb257600080fd5b81518015158114611ece57600080fd5b60008251612fd48184602087016124aa565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_proxyAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReceivingAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"fee\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"reward\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"appliedDiscount\",\"type\":\"uint256\"}],\"name\":\"DiscountApplied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"internalType\":\"structIFeeManager.Quote\",\"name\":\"quote\",\"type\":\"tuple\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101006040523480156200001257600080fd5b50604051620034d8380380620034d8833981016040819052620000359162000288565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001c0565b5050506001600160a01b0384161580620000e057506001600160a01b038316155b80620000f357506001600160a01b038216155b806200010657506001600160a01b038116155b15620001255760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660c05290821660e081905260405163095ea7b360e01b81526004810191909152600019602482015263095ea7b3906044016020604051808303816000875af11580156200018f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b59190620002e5565b505050505062000310565b336001600160a01b038216036200021a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200028357600080fd5b919050565b600080600080608085870312156200029f57600080fd5b620002aa856200026b565b9350620002ba602086016200026b565b9250620002ca604086016200026b565b9150620002da606086016200026b565b905092959194509250565b600060208284031215620002f857600080fd5b815180151581146200030957600080fd5b9392505050565b60805160a05160c05160e051613102620003d660003960008181611185015281816114a601528181611ce20152611f3001526000818161061a0152818161124501526113ec015260008181610a7a01528181610ad101528181610d8801528181610e9701528181611c080152611cb101526000818161079301528181610a9f01528181610b2c01528181610c7601528181610ce501528181610d2401528181610e4001528181610fd70152818161134f015281816118830152611da301526131026000f3fe60806040526004361061010e5760003560e01c806387d6d843116100a5578063d09dc33911610074578063f1387e1611610059578063f1387e1614610382578063f2fde38b14610395578063f65df962146103b557600080fd5b8063d09dc3391461034d578063e389d9a41461036257600080fd5b806387d6d8431461024f5780638da5cb5b1461028d578063c541cbde146102c2578063ce7817d11461032d57600080fd5b806332f5f746116100e157806332f5f746146101f157806340d7f78e14610207578063505380941461021a57806379ba50971461023a57600080fd5b8063013f542b1461011357806301ffc9a714610153578063181f5a77146101835780631d4d84a2146101cf575b600080fd5b34801561011f57600080fd5b5061014061012e366004612532565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561015f57600080fd5b5061017361016e36600461254b565b6103d5565b604051901515815260200161014a565b34801561018f57600080fd5b50604080518082018252601081527f4665654d616e6167657220312e302e30000000000000000000000000000000006020820152905161014a91906125b1565b3480156101db57600080fd5b506101ef6101ea36600461264a565b61046e565b005b3480156101fd57600080fd5b5061014060045481565b6101ef610215366004612695565b610602565b34801561022657600080fd5b506101ef61023536600461272d565b610845565b34801561024657600080fd5b506101ef6108df565b34801561025b57600080fd5b5061014061026a366004612748565b600260209081526000938452604080852082529284528284209052825290205481565b34801561029957600080fd5b5060005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014a565b3480156102ce57600080fd5b506102e26102dd3660046128b4565b6109e1565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a00161014a565b34801561033957600080fd5b506101ef610348366004612955565b610dea565b34801561035957600080fd5b50610140610fa6565b34801561036e57600080fd5b506101ef61037d366004612532565b61105c565b6101ef6103903660046129a6565b61122d565b3480156103a157600080fd5b506101ef6103b0366004612a08565b6113c0565b3480156103c157600080fd5b506101ef6103d0366004612a25565b6113d4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167ff1387e1600000000000000000000000000000000000000000000000000000000148061046857507fffffffff0000000000000000000000000000000000000000000000000000000082167f40d7f78e00000000000000000000000000000000000000000000000000000000145b92915050565b61047661150d565b73ffffffffffffffffffffffffffffffffffffffff831661054b5760008273ffffffffffffffffffffffffffffffffffffffff168277ffffffffffffffffffffffffffffffffffffffffffffffff1660405160006040518083038185875af1925050503d8060008114610505576040519150601f19603f3d011682016040523d82523d6000602084013e61050a565b606091505b5050905080610545576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61058673ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611590565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a15b505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610671576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008267ffffffffffffffff81111561068c5761068c61277f565b6040519080825280602002602001820160405280156106c557816020015b6106b26124a5565b8152602001906001900390816106aa5790505b5090506000806000805b8681101561080e5760008060006107098b8b868181106106f1576106f1612aa4565b90506020028101906107039190612ad3565b8b611664565b92509250925082602001516000146107fa5760405180608001604052808c8c8781811061073857610738612aa4565b905060200281019061074a9190612ad3565b61075391612b3f565b81526020018481526020018381526020018281525088868061077490612baa565b97508151811061078657610786612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036107f3578660010196506107fa565b8560010195505b5050508061080790612baa565b90506106cf565b508215158061081c57508115155b156108325761082d8585858561179e565b61083c565b61083c8534611fb2565b50505050505050565b61084d61150d565b670de0b6b3a764000067ffffffffffffffff82161115610899576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660048190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6040805180820182526000808252602080830182905283518085018552828152808201839052845180860186528381528083018490528551808701909652838652918501839052929382610a3488612be2565b90507fffff000000000000000000000000000000000000000000000000000000000000808216908101610acf57505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050610de1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614158015610b7f57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16886000015173ffffffffffffffffffffffffffffffffffffffff1614155b15610bb6576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b806020019051810190610bcf9190612c3b565b77ffffffffffffffffffffffffffffffffffffffffffffffff92831698509116955063ffffffff1693505050428210159050610c37576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e16600090815260026020908152604080832089845282528083208f51851684529091529020547f00000000000000000000000000000000000000000000000000000000000000009091168752610cc7610caf82670de0b6b3a7640000612cad565b610cb99086612cc0565b670de0b6b3a7640000611fff565b60208801528b5173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911603610d555773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152610dd2565b600454600090610d7190610caf90670de0b6b3a7640000612cfd565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050610dcb610dc183670de0b6b3a7640000612cad565b610cb99083612cc0565b60208a0152505b96995094975094955050505050505b93509350939050565b610df261150d565b670de0b6b3a764000067ffffffffffffffff82161115610e3e576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015610ee657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15610f1d576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611033573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110579190612d10565b905090565b61106461150d565b600081815260036020526040812054908190036110ad576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b60408051808201909152600080825260208201528152602001906001900390816110d257905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff168152508160008151811061113d5761113d612aa4565b60209081029190910101526040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa19906111bc9084903090600401612d89565b600060405180830381600087803b1580156111d657600080fd5b505af11580156111ea573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd98958360405161122091815260200190565b60405180910390a2505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461129c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006112ac868686611664565b92509250925082602001516000036112d0576112c88434611fb2565b505050505050565b604080516001808252818301909252600091816020015b6112ef6124a5565b8152602001906001900390816112e757505060408051608081019091529091508061131a888a612b3f565b8152602001858152602001848152602001838152508160008151811061134257611342612aa4565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff16036113b25761082d85826001600061179e565b61083c85826000600161179e565b6113c861150d565b6113d181612037565b50565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801590611432575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611469576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906314060f23906114df90869086908690600401612dc1565b600060405180830381600087803b1580156114f957600080fd5b505af115801561083c573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff16331461158e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161095c565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526105fd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261212c565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff8516036116dd576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116eb86880188612eaf565b9150506000816116fa90612be2565b6040805160208101909152600081529091507e010000000000000000000000000000000000000000000000000000000000007fffff000000000000000000000000000000000000000000000000000000000000831614611781576000611762898b018b612f73565b955050505050508080602001905181019061177d919061303b565b9150505b61178c8784836109e1565b95509550955050505093509350939050565b60008267ffffffffffffffff8111156117b9576117b961277f565b6040519080825280602002602001820160405280156117fe57816020015b60408051808201909152600080825260208201528152602001906001900390816117d75790505b50905060008267ffffffffffffffff81111561181c5761181c61277f565b60405190808252806020026020018201604052801561186157816020015b604080518082019091526000808252602082015281526020019060019003908161183a5790505b509050600080808080611874888a612cfd565b905060005b81811015611bc3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b82815181106118ca576118ca612aa4565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036119905760405180604001604052808c838151811061191257611912612aa4565b60200260200101516000015181526020018c838151811061193557611935612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525088858061196e90612baa565b96508151811061198057611980612aa4565b6020026020010181905250611a85565b60405180604001604052808c83815181106119ad576119ad612aa4565b60200260200101516000015181526020018c83815181106119d0576119d0612aa4565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16815250878480611a0990612baa565b955081518110611a1b57611a1b612aa4565b60200260200101819052508a8181518110611a3857611a38612aa4565b6020026020010151602001516020015186611a539190612cfd565b95508a8181518110611a6757611a67612aa4565b6020026020010151604001516020015185611a829190612cfd565b94505b8a8181518110611a9757611a97612aa4565b602002602001015160600151600014611bb3578b73ffffffffffffffffffffffffffffffffffffffff168b8281518110611ad357611ad3612aa4565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d8481518110611b1257611b12612aa4565b6020026020010151602001518e8581518110611b3057611b30612aa4565b6020026020010151604001518f8681518110611b4e57611b4e612aa4565b602002602001015160600151604051611baa93929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b611bbc81612baa565b9050611879565b5060003415611c915734861115611c06576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b158015611c6e57600080fd5b505af1158015611c82573d6000803e3d6000fd5b50505050508534039050611cd9565b8515611cd957611cd973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d3089612238565b875115611d6e577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b8152600401611d3b929190612d89565b600060405180830381600087803b158015611d5557600080fd5b505af1158015611d69573d6000803e3d6000fd5b505050505b865115611f9a576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e239190612d10565b851115611ef35760005b8751811015611eb657878181518110611e4857611e48612aa4565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a8481518110611e8457611e84612aa4565b60209081029190910181015151825281019190915260400160002080549091019055611eaf81612baa565b9050611e2d565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b6787604051611ee69190613069565b60405180910390a1611f9a565b6040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b0d9fa1990611f67908a903090600401612d89565b600060405180830381600087803b158015611f8157600080fd5b505af1158015611f95573d6000803e3d6000fd5b505050505b611fa48c82611fb2565b505050505050505050505050565b8015611ffb5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156105fd573d6000803e3d6000fd5b5050565b6000821561202d5781612013600185612cad565b61201d919061307c565b612028906001612cfd565b612030565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036120b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161095c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061218e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122969092919063ffffffff16565b8051909150156105fd57808060200190518101906121ac91906130b7565b6105fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161095c565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526105459085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016115e2565b60606122a584846000856122ad565b949350505050565b60608247101561233f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161095c565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161236891906130d9565b60006040518083038185875af1925050503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50915091506123bb878383876123c6565b979650505050505050565b6060831561245c5782516000036124555773ffffffffffffffffffffffffffffffffffffffff85163b612455576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161095c565b50816122a5565b6122a583838151156124715781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161095c91906125b1565b6040518060800160405280600080191681526020016124ed6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b81526020016125256040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b60006020828403121561254457600080fd5b5035919050565b60006020828403121561255d57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461203057600080fd5b60005b838110156125a8578181015183820152602001612590565b50506000910152565b60208152600082518060208401526125d081604085016020870161258d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b77ffffffffffffffffffffffffffffffffffffffffffffffff811681146113d157600080fd5b60008060006060848603121561265f57600080fd5b833561266a81612602565b9250602084013561267a81612602565b9150604084013561268a81612624565b809150509250925092565b6000806000604084860312156126aa57600080fd5b833567ffffffffffffffff808211156126c257600080fd5b818601915086601f8301126126d657600080fd5b8135818111156126e557600080fd5b8760208260051b85010111156126fa57600080fd5b6020928301955093505084013561268a81612602565b803567ffffffffffffffff8116811461272857600080fd5b919050565b60006020828403121561273f57600080fd5b61203082612710565b60008060006060848603121561275d57600080fd5b833561276881612602565b925060208401359150604084013561268a81612602565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff811182821017156127d1576127d161277f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561281e5761281e61277f565b604052919050565b600082601f83011261283757600080fd5b813567ffffffffffffffff8111156128515761285161277f565b61288260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127d7565b81815284602083860101111561289757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600083850360608112156128ca57600080fd5b84356128d581612602565b9350602085013567ffffffffffffffff8111156128f157600080fd5b6128fd87828801612826565b93505060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08201121561293057600080fd5b506129396127ae565b604085013561294781612602565b815292959194509192509050565b6000806000806080858703121561296b57600080fd5b843561297681612602565b935060208501359250604085013561298d81612602565b915061299b60608601612710565b905092959194509250565b6000806000604084860312156129bb57600080fd5b833567ffffffffffffffff808211156129d357600080fd5b818601915086601f8301126129e757600080fd5b8135818111156129f657600080fd5b8760208285010111156126fa57600080fd5b600060208284031215612a1a57600080fd5b813561203081612602565b600080600060408486031215612a3a57600080fd5b83359250602084013567ffffffffffffffff80821115612a5957600080fd5b818601915086601f830112612a6d57600080fd5b813581811115612a7c57600080fd5b8760208260061b8501011115612a9157600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612b0857600080fd5b83018035915067ffffffffffffffff821115612b2357600080fd5b602001915036819003821315612b3857600080fd5b9250929050565b80356020831015610468577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612bdb57612bdb612b7b565b5060010190565b80516020808301519190811015612c21577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff8116811461272857600080fd5b60008060008060008060c08789031215612c5457600080fd5b86519550612c6460208801612c27565b9450612c7260408801612c27565b93506060870151612c8281612624565b6080880151909350612c9381612624565b9150612ca160a08801612c27565b90509295509295509295565b8181038181111561046857610468612b7b565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612cf857612cf8612b7b565b500290565b8082018082111561046857610468612b7b565b600060208284031215612d2257600080fd5b5051919050565b600081518084526020808501945080840160005b83811015612d7e5781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101612d3d565b509495945050505050565b604081526000612d9c6040830185612d29565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b87811015612e34578335612df381612602565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff612e1f858501612710565b16828401529284019290840190600101612de0565b5098975050505050505050565b600082601f830112612e5257600080fd5b6040516060810181811067ffffffffffffffff82111715612e7557612e7561277f565b604052806060840185811115612e8a57600080fd5b845b81811015612ea4578035835260209283019201612e8c565b509195945050505050565b60008060808385031215612ec257600080fd5b612ecc8484612e41565b9150606083013567ffffffffffffffff811115612ee857600080fd5b612ef485828601612826565b9150509250929050565b600082601f830112612f0f57600080fd5b8135602067ffffffffffffffff821115612f2b57612f2b61277f565b8160051b612f3a8282016127d7565b9283528481018201928281019087851115612f5457600080fd5b83870192505b848310156123bb57823582529183019190830190612f5a565b6000806000806000806101008789031215612f8d57600080fd5b612f978888612e41565b9550606087013567ffffffffffffffff80821115612fb457600080fd5b612fc08a838b01612826565b96506080890135915080821115612fd657600080fd5b612fe28a838b01612efe565b955060a0890135915080821115612ff857600080fd5b6130048a838b01612efe565b945060c0890135935060e089013591508082111561302157600080fd5b5061302e89828a01612826565b9150509295509295509295565b60006020828403121561304d57600080fd5b6130556127ae565b825161306081612602565b81529392505050565b6020815260006120306020830184612d29565b6000826130b2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000602082840312156130c957600080fd5b8151801515811461203057600080fd5b600082516130eb81846020870161258d565b919091019291505056fea164736f6c6343000810000a", } var FeeManagerABI = FeeManagerMetaData.ABI @@ -190,26 +190,27 @@ func (_FeeManager *FeeManagerTransactorRaw) Transact(opts *bind.TransactOpts, me return _FeeManager.Contract.contract.Transact(opts, method, params...) } -func (_FeeManager *FeeManagerCaller) GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerCaller) GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { var out []interface{} err := _FeeManager.contract.Call(opts, &out, "getFeeAndReward", subscriber, report, quote) if err != nil { - return *new(CommonAsset), *new(CommonAsset), err + return *new(CommonAsset), *new(CommonAsset), *new(*big.Int), err } out0 := *abi.ConvertType(out[0], new(CommonAsset)).(*CommonAsset) out1 := *abi.ConvertType(out[1], new(CommonAsset)).(*CommonAsset) + out2 := *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) - return out0, out1, err + return out0, out1, out2, err } -func (_FeeManager *FeeManagerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { return _FeeManager.Contract.GetFeeAndReward(&_FeeManager.CallOpts, subscriber, report, quote) } -func (_FeeManager *FeeManagerCallerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) { +func (_FeeManager *FeeManagerCallerSession) GetFeeAndReward(subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) { return _FeeManager.Contract.GetFeeAndReward(&_FeeManager.CallOpts, subscriber, report, quote) } @@ -463,16 +464,155 @@ func (_FeeManager *FeeManagerTransactorSession) UpdateSubscriberDiscount(subscri return _FeeManager.Contract.UpdateSubscriberDiscount(&_FeeManager.TransactOpts, subscriber, feedId, token, discount) } -func (_FeeManager *FeeManagerTransactor) Withdraw(opts *bind.TransactOpts, assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.contract.Transact(opts, "withdraw", assetAddress, quantity) +func (_FeeManager *FeeManagerTransactor) Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.contract.Transact(opts, "withdraw", assetAddress, recipient, quantity) } -func (_FeeManager *FeeManagerSession) Withdraw(assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, quantity) +func (_FeeManager *FeeManagerSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, recipient, quantity) } -func (_FeeManager *FeeManagerTransactorSession) Withdraw(assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) { - return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, quantity) +func (_FeeManager *FeeManagerTransactorSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) { + return _FeeManager.Contract.Withdraw(&_FeeManager.TransactOpts, assetAddress, recipient, quantity) +} + +type FeeManagerDiscountAppliedIterator struct { + Event *FeeManagerDiscountApplied + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *FeeManagerDiscountAppliedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(FeeManagerDiscountApplied) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(FeeManagerDiscountApplied) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *FeeManagerDiscountAppliedIterator) Error() error { + return it.fail +} + +func (it *FeeManagerDiscountAppliedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type FeeManagerDiscountApplied struct { + ConfigDigest [32]byte + Subscriber common.Address + Fee CommonAsset + Reward CommonAsset + AppliedDiscount *big.Int + Raw types.Log +} + +func (_FeeManager *FeeManagerFilterer) FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*FeeManagerDiscountAppliedIterator, error) { + + var configDigestRule []interface{} + for _, configDigestItem := range configDigest { + configDigestRule = append(configDigestRule, configDigestItem) + } + var subscriberRule []interface{} + for _, subscriberItem := range subscriber { + subscriberRule = append(subscriberRule, subscriberItem) + } + + logs, sub, err := _FeeManager.contract.FilterLogs(opts, "DiscountApplied", configDigestRule, subscriberRule) + if err != nil { + return nil, err + } + return &FeeManagerDiscountAppliedIterator{contract: _FeeManager.contract, event: "DiscountApplied", logs: logs, sub: sub}, nil +} + +func (_FeeManager *FeeManagerFilterer) WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *FeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error) { + + var configDigestRule []interface{} + for _, configDigestItem := range configDigest { + configDigestRule = append(configDigestRule, configDigestItem) + } + var subscriberRule []interface{} + for _, subscriberItem := range subscriber { + subscriberRule = append(subscriberRule, subscriberItem) + } + + logs, sub, err := _FeeManager.contract.WatchLogs(opts, "DiscountApplied", configDigestRule, subscriberRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(FeeManagerDiscountApplied) + if err := _FeeManager.contract.UnpackLog(event, "DiscountApplied", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_FeeManager *FeeManagerFilterer) ParseDiscountApplied(log types.Log) (*FeeManagerDiscountApplied, error) { + event := new(FeeManagerDiscountApplied) + if err := _FeeManager.contract.UnpackLog(event, "DiscountApplied", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil } type FeeManagerInsufficientLinkIterator struct { @@ -1309,6 +1449,7 @@ func (it *FeeManagerWithdrawIterator) Close() error { type FeeManagerWithdraw struct { AdminAddress common.Address + Recipient common.Address AssetAddress common.Address Quantity *big.Int Raw types.Log @@ -1368,6 +1509,8 @@ func (_FeeManager *FeeManagerFilterer) ParseWithdraw(log types.Log) (*FeeManager func (_FeeManager *FeeManager) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { + case _FeeManager.abi.Events["DiscountApplied"].ID: + return _FeeManager.ParseDiscountApplied(log) case _FeeManager.abi.Events["InsufficientLink"].ID: return _FeeManager.ParseInsufficientLink(log) case _FeeManager.abi.Events["LinkDeficitCleared"].ID: @@ -1388,6 +1531,10 @@ func (_FeeManager *FeeManager) ParseLog(log types.Log) (generated.AbigenLog, err } } +func (FeeManagerDiscountApplied) Topic() common.Hash { + return common.HexToHash("0x88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e7125") +} + func (FeeManagerInsufficientLink) Topic() common.Hash { return common.HexToHash("0xf52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b67") } @@ -1413,7 +1560,7 @@ func (FeeManagerSubscriberDiscountUpdated) Topic() common.Hash { } func (FeeManagerWithdraw) Topic() common.Hash { - return common.HexToHash("0x72608e45b52a95a12c2ac7f15ff53f92fc9572c9d84b6e6b5d7f0f7826cf3271") + return common.HexToHash("0x7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f29") } func (_FeeManager *FeeManager) Address() common.Address { @@ -1421,7 +1568,7 @@ func (_FeeManager *FeeManager) Address() common.Address { } type FeeManagerInterface interface { - GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, error) + GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quote IFeeManagerQuote) (CommonAsset, CommonAsset, *big.Int, error) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) @@ -1453,7 +1600,13 @@ type FeeManagerInterface interface { UpdateSubscriberDiscount(opts *bind.TransactOpts, subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error) - Withdraw(opts *bind.TransactOpts, assetAddress common.Address, quantity *big.Int) (*types.Transaction, error) + Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) + + FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*FeeManagerDiscountAppliedIterator, error) + + WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *FeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error) + + ParseDiscountApplied(log types.Log) (*FeeManagerDiscountApplied, error) FilterInsufficientLink(opts *bind.FilterOpts) (*FeeManagerInsufficientLinkIterator, error) diff --git a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go index ed4c621842c..236eeaa5c1a 100644 --- a/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go +++ b/core/gethwrappers/llo-feeds/generated/reward_manager/reward_manager.go @@ -41,8 +41,8 @@ type IRewardManagerFeePayment struct { } var RewardManagerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payee\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b5060405162002080380380620020808339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611e85620001fb60003960008181610ca70152610ee20152611e856000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806359256201116100b25780638ac85a5c11610081578063b0d9fa1911610066578063b0d9fa1914610377578063cd5f72921461038a578063f2fde38b1461039d57600080fd5b80638ac85a5c1461032e5780638da5cb5b1461035957600080fd5b806359256201146102b857806360122608146102db5780636992922f1461030657806379ba50971461032657600080fd5b8063276e766011610109578063472d35b9116100ee578063472d35b91461027f5780634944832f146102925780634d322084146102a557600080fd5b8063276e76601461020c57806339ee81e11461025157600080fd5b806301ffc9a71461013b5780630f3c34d1146101a557806314060f23146101ba578063181f5a77146101cd575b600080fd5b6101906101493660046117aa565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101b86101b336600461186a565b6103b0565b005b6101b86101c836600461195c565b6103be565b604080518082018252601381527f5265776172644d616e6167657220302e302e31000000000000000000000000006020820152905161019c91906119cc565b60075461022c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61027161025f366004611a1d565b60026020526000908152604090205481565b60405190815260200161019c565b6101b861028d366004611a5f565b610574565b6101b86102a036600461195c565b610642565b6101b86102b3366004611a81565b6107c4565b6101906102c6366004611a1d565b60056020526000908152604090205460ff1681565b6102716102e9366004611b00565b600360209081526000928352604080842090915290825290205481565b610319610314366004611a5f565b610903565b60405161019c9190611b2c565b6101b8610a34565b61027161033c366004611b00565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff1661022c565b6101b8610385366004611b70565b610b36565b610271610398366004611a1d565b610d10565b6101b86103ab366004611a5f565b610d31565b6103ba3382610d45565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906103fe575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610435576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610470576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104b9576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610535838383670de0b6b3a7640000610f12565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610567929190611bdc565b60405180910390a2505050565b61057c611123565b73ffffffffffffffffffffffffffffffffffffffff81166105c9576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b61064a611123565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061068057610680611c51565b6020026020010181815250506000805b838110156107765760008585838181106106ac576106ac611c51565b6106c29260206040909202019081019150611a5f565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205491925081900361072e576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61075f87878581811061074357610743611c51565b6107599260206040909202019081019150611a5f565b86610d45565b5092909201915061076f81611caf565b9050610690565b5061078385858584610f12565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe685856040516107b5929190611bdc565b60405180910390a25050505050565b826107e460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415801561083657506000818152600460209081526040808320338452909152902054155b1561086d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092526000916020808301908036833701905050905084816000815181106108a3576108a3611c51565b60200260200101818152505060005b838110156108fb576108ea8585838181106108cf576108cf611c51565b90506020020160208101906108e49190611a5f565b83610d45565b506108f481611caf565b90506108b2565b505050505050565b60065460609060008167ffffffffffffffff811115610924576109246117ec565b60405190808252806020026020018201604052801561094d578160200160208202803683370190505b5090506000805b83811015610a2a5760006006828154811061097157610971611c51565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8c16855290925291205490915015610a19576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8c168552909252909120548114610a175781858580600101965081518110610a0a57610a0a611c51565b6020026020010181815250505b505b50610a2381611caf565b9050610954565b5090949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590610b76575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610bad576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610c8c57848482818110610bcb57610bcb611c51565b9050604002016020016020810190610be39190611d0f565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c1357610c13611c51565b6040908102929092013583525060208201929092520160002080549091019055848482818110610c4557610c45611c51565b9050604002016020016020810190610c5d9190611d0f565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610c8590611caf565b9050610bb1565b50610ccf73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168330846111a6565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d0293929190611d2a565b60405180910390a150505050565b60068181548110610d2057600080fd5b600091825260209091200154905081565b610d39611123565b610d4281611288565b50565b60008060005b8351811015610ec1576000848281518110610d6857610d68611c51565b6020026020010151905060006002600083815260200190815260200160002054905080600003610d99575050610eb1565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e025750505050610eb1565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610e4d57610e4d611c51565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610ea4919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610eba81611caf565b9050610d4b565b508015610f0957610f0973ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016858361137d565b90505b92915050565b610f6d8383808060200260200160405190810160405280939291908181526020016000905b82821015610f6357610f5460408302860136819003810190611db1565b81526020019060010190610f37565b50505050506113d8565b15610fa4576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b838110156110e2576000858583818110610fc457610fc4611c51565b9050604002016020016020810190610fdc9190611e0c565b67ffffffffffffffff1690506000868684818110610ffc57610ffc611c51565b6110129260206040909202019081019150611a5f565b905073ffffffffffffffffffffffffffffffffffffffff8116611061576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160000361109b576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff90941683529290522081905591909101906110db81611caf565b9050610fa8565b5081811461111c576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ab1565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112829085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261148f565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611307576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ab1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113d39084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611200565b505050565b6000805b82518110156114865760006113f2826001611e27565b90505b835181101561147d5783818151811061141057611410611c51565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1684838151811061144457611444611c51565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1603611475575060019392505050565b6001016113f5565b506001016113dc565b50600092915050565b60006114f1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661159b9092919063ffffffff16565b8051909150156113d3578080602001905181019061150f9190611e3a565b6113d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ab1565b60606115aa84846000856115b2565b949350505050565b606082471015611644576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610ab1565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161166d9190611e5c565b60006040518083038185875af1925050503d80600081146116aa576040519150601f19603f3d011682016040523d82523d6000602084013e6116af565b606091505b50915091506116c0878383876116cb565b979650505050505050565b6060831561176157825160000361175a5773ffffffffffffffffffffffffffffffffffffffff85163b61175a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ab1565b50816115aa565b6115aa83838151156117765781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab191906119cc565b6000602082840312156117bc57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f0957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611862576118626117ec565b604052919050565b6000602080838503121561187d57600080fd5b823567ffffffffffffffff8082111561189557600080fd5b818501915085601f8301126118a957600080fd5b8135818111156118bb576118bb6117ec565b8060051b91506118cc84830161181b565b81815291830184019184810190888411156118e657600080fd5b938501935b83851015611904578435825293850193908501906118eb565b98975050505050505050565b60008083601f84011261192257600080fd5b50813567ffffffffffffffff81111561193a57600080fd5b6020830191508360208260061b850101111561195557600080fd5b9250929050565b60008060006040848603121561197157600080fd5b83359250602084013567ffffffffffffffff81111561198f57600080fd5b61199b86828701611910565b9497909650939450505050565b60005b838110156119c35781810151838201526020016119ab565b50506000910152565b60208152600082518060208401526119eb8160408501602087016119a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611a2f57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a5a57600080fd5b919050565b600060208284031215611a7157600080fd5b611a7a82611a36565b9392505050565b600080600060408486031215611a9657600080fd5b83359250602084013567ffffffffffffffff80821115611ab557600080fd5b818601915086601f830112611ac957600080fd5b813581811115611ad857600080fd5b8760208260051b8501011115611aed57600080fd5b6020830194508093505050509250925092565b60008060408385031215611b1357600080fd5b82359150611b2360208401611a36565b90509250929050565b6020808252825182820181905260009190848201906040850190845b81811015611b6457835183529284019291840191600101611b48565b50909695505050505050565b600080600060408486031215611b8557600080fd5b833567ffffffffffffffff811115611b9c57600080fd5b611ba886828701611910565b9094509250611bbb905060208501611a36565b90509250925092565b803567ffffffffffffffff81168114611a5a57600080fd5b6020808252818101839052600090604080840186845b87811015611c445773ffffffffffffffffffffffffffffffffffffffff611c1883611a36565b16835267ffffffffffffffff611c2f868401611bc4565b16838601529183019190830190600101611bf2565b5090979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ce057611ce0611c80565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611a5a57600080fd5b600060208284031215611d2157600080fd5b611a7a82611ce7565b60408082528181018490526000908560608401835b87811015611d865782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611d71828601611ce7565b16908301529183019190830190600101611d3f565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611dc357600080fd5b6040516040810181811067ffffffffffffffff82111715611de657611de66117ec565b604052611df283611a36565b8152611e0060208401611bc4565b60208201529392505050565b600060208284031215611e1e57600080fd5b611a7a82611bc4565b80820180821115610f0c57610f0c611c80565b600060208284031215611e4c57600080fd5b81518015158114610f0957600080fd5b60008251611e6e8184602087016119a8565b919091019291505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endIndex\",\"type\":\"uint256\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManagerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620020ec380380620020ec8339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b608051611ef1620001fb60003960008181610cda0152610f150152611ef16000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80634d322084116100b25780638ac85a5c11610081578063b0d9fa1911610066578063b0d9fa1914610377578063cd5f72921461038a578063f2fde38b1461039d57600080fd5b80638ac85a5c1461032e5780638da5cb5b1461035957600080fd5b80634d322084146102c557806359256201146102d857806360122608146102fb57806379ba50971461032657600080fd5b8063276e76601161010957806347226475116100ee578063472264751461027f578063472d35b91461029f5780634944832f146102b257600080fd5b8063276e76601461020c57806339ee81e11461025157600080fd5b806301ffc9a71461013b5780630f3c34d1146101a557806314060f23146101ba578063181f5a77146101cd575b600080fd5b6101906101493660046117dd565b7fffffffff00000000000000000000000000000000000000000000000000000000167fb0d9fa19000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101b86101b336600461189d565b6103b0565b005b6101b86101c836600461198f565b6103be565b604080518082018252601381527f5265776172644d616e6167657220312e302e30000000000000000000000000006020820152905161019c91906119ff565b60075461022c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b61027161025f366004611a50565b60026020526000908152604090205481565b60405190815260200161019c565b61029261028d366004611a92565b610574565b60405161019c9190611ac5565b6101b86102ad366004611b09565b6106fe565b6101b86102c036600461198f565b6107cc565b6101b86102d3366004611b2b565b61094e565b6101906102e6366004611a50565b60056020526000908152604090205460ff1681565b610271610309366004611baa565b600360209081526000928352604080842090915290825290205481565b6101b8610a8d565b61027161033c366004611baa565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff1661022c565b6101b8610385366004611bd6565b610b8f565b610271610398366004611a50565b610d43565b6101b86103ab366004611b09565b610d64565b6103ba3382610d78565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906103fe575060075473ffffffffffffffffffffffffffffffffffffffff163314155b15610435576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819003610470576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff16156104b9576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169091179055610535838383670de0b6b3a7640000610f45565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610567929190611c42565b60405180910390a2505050565b6006546060906000818411610589578361058b565b815b9050808511156105c7576040517fa22caccc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006105d38683611cd9565b67ffffffffffffffff8111156105eb576105eb61181f565b604051908082528060200260200182016040528015610614578160200160208202803683370190505b5090506000865b838110156106f15760006006828154811061063857610638611cec565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8f168552909252912054909150156106e0576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8f1685529092529091205481146106de57818585806001019650815181106106d1576106d1611cec565b6020026020010181815250505b505b506106ea81611d1b565b905061061b565b5090979650505050505050565b610706611156565b73ffffffffffffffffffffffffffffffffffffffff8116610753576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b49060200160405180910390a150565b6107d4611156565b60408051600180825281830190925260009160208083019080368337019050509050838160008151811061080a5761080a611cec565b6020026020010181815250506000805b8381101561090057600085858381811061083657610836611cec565b61084c9260206040909202019081019150611b09565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff851684529091528120549192508190036108b8576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108e98787858181106108cd576108cd611cec565b6108e39260206040909202019081019150611b09565b86610d78565b509290920191506108f981611d1b565b905061081a565b5061090d85858584610f45565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe6858560405161093f929190611c42565b60405180910390a25050505050565b8261096e60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141580156109c057506000818152600460209081526040808320338452909152902054155b156109f7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001808252818301909252600091602080830190803683370190505090508481600081518110610a2d57610a2d611cec565b60200260200101818152505060005b83811015610a8557610a74858583818110610a5957610a59611cec565b9050602002016020810190610a6e9190611b09565b83610d78565b50610a7e81611d1b565b9050610a3c565b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60075473ffffffffffffffffffffffffffffffffffffffff163314610be0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015610cbf57848482818110610bfe57610bfe611cec565b9050604002016020016020810190610c169190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610c4657610c46611cec565b6040908102929092013583525060208201929092520160002080549091019055848482818110610c7857610c78611cec565b9050604002016020016020810190610c909190611d7b565b77ffffffffffffffffffffffffffffffffffffffffffffffff168201915080610cb890611d1b565b9050610be4565b50610d0273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168330846111d9565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66848484604051610d3593929190611d96565b60405180910390a150505050565b60068181548110610d5357600080fd5b600091825260209091200154905081565b610d6c611156565b610d75816112bb565b50565b60008060005b8351811015610ef4576000848281518110610d9b57610d9b611cec565b6020026020010151905060006002600083815260200190815260200160002054905080600003610dcc575050610ee4565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a764000090830204905080600003610e355750505050610ee4565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d168085529252909120849055885196820196899087908110610e8057610e80611cec565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051610ed7919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b610eed81611d1b565b9050610d7e565b508015610f3c57610f3c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836113b0565b90505b92915050565b610fa08383808060200260200160405190810160405280939291908181526020016000905b82821015610f9657610f8760408302860136819003810190611e1d565b81526020019060010190610f6a565b505050505061140b565b15610fd7576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b83811015611115576000858583818110610ff757610ff7611cec565b905060400201602001602081019061100f9190611e78565b67ffffffffffffffff169050600086868481811061102f5761102f611cec565b6110459260206040909202019081019150611b09565b905073ffffffffffffffffffffffffffffffffffffffff8116611094576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816000036110ce576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff909416835292905220819055919091019061110e81611d1b565b9050610fdb565b5081811461114f576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146111d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0a565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526112b59085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526114c2565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114069084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611233565b505050565b6000805b82518110156114b9576000611425826001611e93565b90505b83518110156114b05783818151811061144357611443611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1684838151811061147757611477611cec565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16036114a8575060019392505050565b600101611428565b5060010161140f565b50600092915050565b6000611524826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166115ce9092919063ffffffff16565b80519091501561140657808060200190518101906115429190611ea6565b611406576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b0a565b60606115dd84846000856115e5565b949350505050565b606082471015611677576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b0a565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516116a09190611ec8565b60006040518083038185875af1925050503d80600081146116dd576040519150601f19603f3d011682016040523d82523d6000602084013e6116e2565b606091505b50915091506116f3878383876116fe565b979650505050505050565b6060831561179457825160000361178d5773ffffffffffffffffffffffffffffffffffffffff85163b61178d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b0a565b50816115dd565b6115dd83838151156117a95781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0a91906119ff565b6000602082840312156117ef57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f3c57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156118955761189561181f565b604052919050565b600060208083850312156118b057600080fd5b823567ffffffffffffffff808211156118c857600080fd5b818501915085601f8301126118dc57600080fd5b8135818111156118ee576118ee61181f565b8060051b91506118ff84830161184e565b818152918301840191848101908884111561191957600080fd5b938501935b838510156119375784358252938501939085019061191e565b98975050505050505050565b60008083601f84011261195557600080fd5b50813567ffffffffffffffff81111561196d57600080fd5b6020830191508360208260061b850101111561198857600080fd5b9250929050565b6000806000604084860312156119a457600080fd5b83359250602084013567ffffffffffffffff8111156119c257600080fd5b6119ce86828701611943565b9497909650939450505050565b60005b838110156119f65781810151838201526020016119de565b50506000910152565b6020815260008251806020840152611a1e8160408501602087016119db565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600060208284031215611a6257600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b919050565b600080600060608486031215611aa757600080fd5b611ab084611a69565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015611afd57835183529284019291840191600101611ae1565b50909695505050505050565b600060208284031215611b1b57600080fd5b611b2482611a69565b9392505050565b600080600060408486031215611b4057600080fd5b83359250602084013567ffffffffffffffff80821115611b5f57600080fd5b818601915086601f830112611b7357600080fd5b813581811115611b8257600080fd5b8760208260051b8501011115611b9757600080fd5b6020830194508093505050509250925092565b60008060408385031215611bbd57600080fd5b82359150611bcd60208401611a69565b90509250929050565b600080600060408486031215611beb57600080fd5b833567ffffffffffffffff811115611c0257600080fd5b611c0e86828701611943565b9094509250611c21905060208501611a69565b90509250925092565b803567ffffffffffffffff81168114611a8d57600080fd5b6020808252818101839052600090604080840186845b878110156106f15773ffffffffffffffffffffffffffffffffffffffff611c7e83611a69565b16835267ffffffffffffffff611c95868401611c2a565b16838601529183019190830190600101611c58565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610f3f57610f3f611caa565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611d4c57611d4c611caa565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611a8d57600080fd5b600060208284031215611d8d57600080fd5b611b2482611d53565b60408082528181018490526000908560608401835b87811015611df25782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff611ddd828601611d53565b16908301529183019190830190600101611dab565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b600060408284031215611e2f57600080fd5b6040516040810181811067ffffffffffffffff82111715611e5257611e5261181f565b604052611e5e83611a69565b8152611e6c60208401611c2a565b60208201529392505050565b600060208284031215611e8a57600080fd5b611b2482611c2a565b80820180821115610f3f57610f3f611caa565b600060208284031215611eb857600080fd5b81518015158114610f3c57600080fd5b60008251611eda8184602087016119db565b919091019291505056fea164736f6c6343000810000a", } var RewardManagerABI = RewardManagerMetaData.ABI @@ -181,9 +181,9 @@ func (_RewardManager *RewardManagerTransactorRaw) Transact(opts *bind.TransactOp return _RewardManager.Contract.contract.Transact(opts, method, params...) } -func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address) ([][32]byte, error) { +func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { var out []interface{} - err := _RewardManager.contract.Call(opts, &out, "getAvailableRewardPoolIds", recipient) + err := _RewardManager.contract.Call(opts, &out, "getAvailableRewardPoolIds", recipient, startIndex, endIndex) if err != nil { return *new([][32]byte), err @@ -195,12 +195,12 @@ func (_RewardManager *RewardManagerCaller) GetAvailableRewardPoolIds(opts *bind. } -func (_RewardManager *RewardManagerSession) GetAvailableRewardPoolIds(recipient common.Address) ([][32]byte, error) { - return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient) +func (_RewardManager *RewardManagerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { + return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient, startIndex, endIndex) } -func (_RewardManager *RewardManagerCallerSession) GetAvailableRewardPoolIds(recipient common.Address) ([][32]byte, error) { - return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient) +func (_RewardManager *RewardManagerCallerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) { + return _RewardManager.Contract.GetAvailableRewardPoolIds(&_RewardManager.CallOpts, recipient, startIndex, endIndex) } func (_RewardManager *RewardManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { @@ -425,16 +425,16 @@ func (_RewardManager *RewardManagerTransactorSession) ClaimRewards(poolIds [][32 return _RewardManager.Contract.ClaimRewards(&_RewardManager.TransactOpts, poolIds) } -func (_RewardManager *RewardManagerTransactor) OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.contract.Transact(opts, "onFeePaid", payments, payee) +func (_RewardManager *RewardManagerTransactor) OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.contract.Transact(opts, "onFeePaid", payments, payer) } -func (_RewardManager *RewardManagerSession) OnFeePaid(payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payee) +func (_RewardManager *RewardManagerSession) OnFeePaid(payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payer) } -func (_RewardManager *RewardManagerTransactorSession) OnFeePaid(payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) { - return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payee) +func (_RewardManager *RewardManagerTransactorSession) OnFeePaid(payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) { + return _RewardManager.Contract.OnFeePaid(&_RewardManager.TransactOpts, payments, payer) } func (_RewardManager *RewardManagerTransactor) PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error) { @@ -676,7 +676,7 @@ func (it *RewardManagerFeePaidIterator) Close() error { type RewardManagerFeePaid struct { Payments []IRewardManagerFeePayment - Payee common.Address + Payer common.Address Raw types.Log } @@ -1318,7 +1318,7 @@ func (_RewardManager *RewardManager) Address() common.Address { } type RewardManagerInterface interface { - GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address) ([][32]byte, error) + GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) Owner(opts *bind.CallOpts) (common.Address, error) @@ -1342,7 +1342,7 @@ type RewardManagerInterface interface { ClaimRewards(opts *bind.TransactOpts, poolIds [][32]byte) (*types.Transaction, error) - OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payee common.Address) (*types.Transaction, error) + OnFeePaid(opts *bind.TransactOpts, payments []IRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error) diff --git a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go index 77e76dfd70b..12e5e28948e 100644 --- a/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go +++ b/core/gethwrappers/llo-feeds/generated/verifier_proxy/verifier_proxy.go @@ -36,8 +36,8 @@ type CommonAddressAndWeight struct { } var VerifierProxyMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadVerification\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"ConfigDigestAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"VerifierAlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VerifierInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"VerifierNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAccessController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAccessController\",\"type\":\"address\"}],\"name\":\"AccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManager\",\"type\":\"address\"}],\"name\":\"FeeManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"oldConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierUnset\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"getVerifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"initializeVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"name\":\"setAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"feeManager\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"currentConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"addressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"unsetVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"verifiedReport\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"verifiedReports\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b5060405162001ac538038062001ac5833981016040819052620000349162000193565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050600480546001600160a01b0319166001600160a01b03939093169290921790915550620001c5565b336001600160a01b03821603620001425760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001a657600080fd5b81516001600160a01b0381168114620001be57600080fd5b9392505050565b6118f080620001d56000396000f3fe6080604052600436106100dd5760003560e01c80638da5cb5b1161007f578063b011b24711610059578063b011b2471461028e578063eeb7b248146102ae578063f08391d8146102f1578063f2fde38b1461031157600080fd5b80638da5cb5b146102235780638e760afe1461024e57806394ba28461461026157600080fd5b80636e914094116100bb5780636e914094146101ae57806379ba5097146101ce57806383490cd7146101e35780638c2a4d531461020357600080fd5b8063181f5a77146100e257806338416b5b1461013a578063472d35b91461018c575b600080fd5b3480156100ee57600080fd5b5060408051808201909152601381527f566572696669657250726f787920312e312e300000000000000000000000000060208201525b6040516101319190611216565b60405180910390f35b34801561014657600080fd5b506005546101679073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610131565b34801561019857600080fd5b506101ac6101a7366004611252565b610331565b005b3480156101ba57600080fd5b506101ac6101c936600461126f565b61040d565b3480156101da57600080fd5b506101ac6104fe565b6101f66101f1366004611288565b6105fb565b60405161013191906112fd565b34801561020f57600080fd5b506101ac61021e366004611252565b610859565b34801561022f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610167565b61012461025c36600461137d565b610a8a565b34801561026d57600080fd5b506004546101679073ffffffffffffffffffffffffffffffffffffffff1681565b34801561029a57600080fd5b506101ac6102a93660046113dd565b610c3e565b3480156102ba57600080fd5b506101676102c936600461126f565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156102fd57600080fd5b506101ac61030c366004611252565b610e64565b34801561031d57600080fd5b506101ac61032c366004611252565b610eeb565b610339610eff565b73ffffffffffffffffffffffffffffffffffffffff8116610386576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f0391015b60405180910390a15050565b610415610eff565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610479576040517fb151802b000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b6000828152600360205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f11dc15c4b8ac2b183166cc8427e5385a5ece8308217a4217338c6a7614845c4c90610401908490849091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60015473ffffffffffffffffffffffffffffffffffffffff16331461057f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610470565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60045460609073ffffffffffffffffffffffffffffffffffffffff1680158015906106bb57506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061067890339060009036906004016114a9565b602060405180830381865afa158015610695573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b991906114d9565b155b156106f2576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff16801561079c576040517f40d7f78e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906340d7f78e903490610769908990899033906004016114fb565b6000604051808303818588803b15801561078257600080fd5b505af1158015610796573d6000803e3d6000fd5b50505050505b8367ffffffffffffffff8111156107b5576107b56115f0565b6040519080825280602002602001820160405280156107e857816020015b60608152602001906001900390816107d35790505b50925060005b848110156108505761082286868381811061080b5761080b61161f565b905060200281019061081d919061164e565b610f82565b8482815181106108345761083461161f565b602002602001018190525080610849906116ba565b90506107ee565b50505092915050565b610861610eff565b8073ffffffffffffffffffffffffffffffffffffffff81166108af576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f3d3ac1b500000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095d91906114d9565b610993576040517f75b0527a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205460ff1615610a0b576040517f4e01ccfd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610470565b73ffffffffffffffffffffffffffffffffffffffff821660008181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f1f2cd7c97f4d801b5efe26cc409617c1fd6c5ef786e79aacb90af40923e4e8e99101610401565b60045460609073ffffffffffffffffffffffffffffffffffffffff168015801590610b4a57506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890610b0790339060009036906004016114a9565b602060405180830381865afa158015610b24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4891906114d9565b155b15610b81576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610c2b576040517ff1387e1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063f1387e16903490610bf890899089903390600401611719565b6000604051808303818588803b158015610c1157600080fd5b505af1158015610c25573d6000803e3d6000fd5b50505050505b610c358585610f82565b95945050505050565b600083815260036020526040902054839073ffffffffffffffffffffffffffffffffffffffff168015610cbc576040517f375d1fe60000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82166024820152604401610470565b3360009081526002602052604090205460ff16610d05576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558215610e1d5760055473ffffffffffffffffffffffffffffffffffffffff16610d90576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517ff65df96200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063f65df96290610dea90889088908890600401611753565b600060405180830381600087803b158015610e0457600080fd5b505af1158015610e18573d6000803e3d6000fd5b505050505b6040805187815260208101879052338183015290517fbeb513e532542a562ac35699e7cd9ae7d198dcd3eee15bada6c857d28ceaddcf9181900360600190a1505050505050565b610e6c610eff565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b69101610401565b610ef3610eff565b610efc816110b3565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f80576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610470565b565b60606000610f9083856117dc565b60008181526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1680610ff2576040517fb151802b00000000000000000000000000000000000000000000000000000000815260048101839052602401610470565b6040517f3d3ac1b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690633d3ac1b59061104890889088903390600401611719565b6000604051808303816000875af1158015611067573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c359190810190611818565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff821603611132576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610470565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b838110156111c35781810151838201526020016111ab565b50506000910152565b600081518084526111e48160208601602086016111a8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061122960208301846111cc565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610efc57600080fd5b60006020828403121561126457600080fd5b813561122981611230565b60006020828403121561128157600080fd5b5035919050565b6000806020838503121561129b57600080fd5b823567ffffffffffffffff808211156112b357600080fd5b818501915085601f8301126112c757600080fd5b8135818111156112d657600080fd5b8660208260051b85010111156112eb57600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015611370577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261135e8583516111cc565b94509285019290850190600101611324565b5092979650505050505050565b6000806020838503121561139057600080fd5b823567ffffffffffffffff808211156113a857600080fd5b818501915085601f8301126113bc57600080fd5b8135818111156113cb57600080fd5b8660208285010111156112eb57600080fd5b600080600080606085870312156113f357600080fd5b8435935060208501359250604085013567ffffffffffffffff8082111561141957600080fd5b818701915087601f83011261142d57600080fd5b81358181111561143c57600080fd5b8860208260061b850101111561145157600080fd5b95989497505060200194505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610c35604083018486611460565b6000602082840312156114eb57600080fd5b8151801515811461122957600080fd5b6040808252810183905260006060600585901b8301810190830186835b878110156115c7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18a360301811261157957600080fd5b8901602081810191359067ffffffffffffffff82111561159857600080fd5b8136038313156115a757600080fd5b6115b2878385611460565b96509485019493909301925050600101611518565b50505073ffffffffffffffffffffffffffffffffffffffff841660208401529050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261168357600080fd5b83018035915067ffffffffffffffff82111561169e57600080fd5b6020019150368190038213156116b357600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611712577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60408152600061172d604083018587611460565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b838152604060208083018290528282018490526000919085906060850184805b888110156117cd57843561178681611230565b73ffffffffffffffffffffffffffffffffffffffff1683528484013567ffffffffffffffff81168082146117b8578384fd5b84860152509385019391850191600101611773565b50909998505050505050505050565b803560208310156110ad577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b60006020828403121561182a57600080fd5b815167ffffffffffffffff8082111561184257600080fd5b818401915084601f83011261185657600080fd5b815181811115611868576118686115f0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156118ae576118ae6115f0565b816040528281528760208487010111156118c757600080fd5b6118d88360208301602088016111a8565b97965050505050505056fea164736f6c6343000810000a", + ABI: "[{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadVerification\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"ConfigDigestAlreadySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeManagerInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifier\",\"type\":\"address\"}],\"name\":\"VerifierAlreadyInitialized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VerifierInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"VerifierNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAccessController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAccessController\",\"type\":\"address\"}],\"name\":\"AccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManager\",\"type\":\"address\"}],\"name\":\"FeeManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"oldConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierUnset\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"getVerifier\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"initializeVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractAccessControllerInterface\",\"name\":\"accessController\",\"type\":\"address\"}],\"name\":\"setAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIVerifierFeeManager\",\"name\":\"feeManager\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"currentConfigDigest\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"newConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"addressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"unsetVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"verifiedReports\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b5060405162001c6138038062001c61833981016040819052620000349162000193565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050600480546001600160a01b0319166001600160a01b03939093169290921790915550620001c5565b336001600160a01b03821603620001425760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001a657600080fd5b81516001600160a01b0381168114620001be57600080fd5b9392505050565b611a8c80620001d56000396000f3fe6080604052600436106100dd5760003560e01c80638da5cb5b1161007f578063b011b24711610059578063b011b2471461028e578063eeb7b248146102ae578063f08391d8146102f1578063f2fde38b1461031157600080fd5b80638da5cb5b146102235780638e760afe1461024e57806394ba28461461026157600080fd5b80636e914094116100bb5780636e914094146101ae57806379ba5097146101ce57806383490cd7146101e35780638c2a4d531461020357600080fd5b8063181f5a77146100e257806338416b5b1461013a578063472d35b91461018c575b600080fd5b3480156100ee57600080fd5b5060408051808201909152601381527f566572696669657250726f787920312e312e300000000000000000000000000060208201525b60405161013191906113b2565b60405180910390f35b34801561014657600080fd5b506005546101679073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610131565b34801561019857600080fd5b506101ac6101a73660046113ee565b610331565b005b3480156101ba57600080fd5b506101ac6101c936600461140b565b6105a9565b3480156101da57600080fd5b506101ac61069a565b6101f66101f1366004611424565b610797565b6040516101319190611499565b34801561020f57600080fd5b506101ac61021e3660046113ee565b6109f5565b34801561022f57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610167565b61012461025c366004611519565b610c26565b34801561026d57600080fd5b506004546101679073ffffffffffffffffffffffffffffffffffffffff1681565b34801561029a57600080fd5b506101ac6102a9366004611579565b610dda565b3480156102ba57600080fd5b506101676102c936600461140b565b60009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156102fd57600080fd5b506101ac61030c3660046113ee565b611000565b34801561031d57600080fd5b506101ac61032c3660046113ee565b611087565b61033961109b565b73ffffffffffffffffffffffffffffffffffffffff8116610386576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527ff1387e1600000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610410573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043491906115fc565b15806104eb57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f40d7f78e00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e991906115fc565b155b15610522576040517f8238941900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f0391015b60405180910390a15050565b6105b161109b565b60008181526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610615576040517fb151802b000000000000000000000000000000000000000000000000000000008152600481018390526024015b60405180910390fd5b6000828152600360205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f11dc15c4b8ac2b183166cc8427e5385a5ece8308217a4217338c6a7614845c4c9061059d908490849091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60015473ffffffffffffffffffffffffffffffffffffffff16331461071b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161060c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60045460609073ffffffffffffffffffffffffffffffffffffffff16801580159061085757506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf8906108149033906000903690600401611667565b602060405180830381865afa158015610831573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085591906115fc565b155b1561088e576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610938576040517f40d7f78e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906340d7f78e90349061090590899089903390600401611697565b6000604051808303818588803b15801561091e57600080fd5b505af1158015610932573d6000803e3d6000fd5b50505050505b8367ffffffffffffffff8111156109515761095161178c565b60405190808252806020026020018201604052801561098457816020015b606081526020019060019003908161096f5790505b50925060005b848110156109ec576109be8686838181106109a7576109a76117bb565b90506020028101906109b991906117ea565b61111e565b8482815181106109d0576109d06117bb565b6020026020010181905250806109e590611856565b905061098a565b50505092915050565b6109fd61109b565b8073ffffffffffffffffffffffffffffffffffffffff8116610a4b576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f3d3ac1b500000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906115fc565b610b2f576040517f75b0527a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205460ff1615610ba7576040517f4e01ccfd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161060c565b73ffffffffffffffffffffffffffffffffffffffff821660008181526002602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f1f2cd7c97f4d801b5efe26cc409617c1fd6c5ef786e79aacb90af40923e4e8e9910161059d565b60045460609073ffffffffffffffffffffffffffffffffffffffff168015801590610ce657506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf890610ca39033906000903690600401611667565b602060405180830381865afa158015610cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce491906115fc565b155b15610d1d576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055473ffffffffffffffffffffffffffffffffffffffff168015610dc7576040517ff1387e1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063f1387e16903490610d94908990899033906004016118b5565b6000604051808303818588803b158015610dad57600080fd5b505af1158015610dc1573d6000803e3d6000fd5b50505050505b610dd1858561111e565b95945050505050565b600083815260036020526040902054839073ffffffffffffffffffffffffffffffffffffffff168015610e58576040517f375d1fe60000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161060c565b3360009081526002602052604090205460ff16610ea1576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260036020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790558215610fb95760055473ffffffffffffffffffffffffffffffffffffffff16610f2c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517ff65df96200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063f65df96290610f86908890889088906004016118ef565b600060405180830381600087803b158015610fa057600080fd5b505af1158015610fb4573d6000803e3d6000fd5b505050505b6040805187815260208101879052338183015290517fbeb513e532542a562ac35699e7cd9ae7d198dcd3eee15bada6c857d28ceaddcf9181900360600190a1505050505050565b61100861109b565b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b6910161059d565b61108f61109b565b6110988161124f565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461111c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161060c565b565b6060600061112c8385611978565b60008181526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff168061118e576040517fb151802b0000000000000000000000000000000000000000000000000000000081526004810183905260240161060c565b6040517f3d3ac1b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690633d3ac1b5906111e4908890889033906004016118b5565b6000604051808303816000875af1158015611203573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610dd191908101906119b4565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff8216036112ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161060c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b8381101561135f578181015183820152602001611347565b50506000910152565b60008151808452611380816020860160208601611344565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113c56020830184611368565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461109857600080fd5b60006020828403121561140057600080fd5b81356113c5816113cc565b60006020828403121561141d57600080fd5b5035919050565b6000806020838503121561143757600080fd5b823567ffffffffffffffff8082111561144f57600080fd5b818501915085601f83011261146357600080fd5b81358181111561147257600080fd5b8660208260051b850101111561148757600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561150c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526114fa858351611368565b945092850192908501906001016114c0565b5092979650505050505050565b6000806020838503121561152c57600080fd5b823567ffffffffffffffff8082111561154457600080fd5b818501915085601f83011261155857600080fd5b81358181111561156757600080fd5b86602082850101111561148757600080fd5b6000806000806060858703121561158f57600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156115b557600080fd5b818701915087601f8301126115c957600080fd5b8135818111156115d857600080fd5b8860208260061b85010111156115ed57600080fd5b95989497505060200194505050565b60006020828403121561160e57600080fd5b815180151581146113c557600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000610dd160408301848661161e565b6040808252810183905260006060600585901b8301810190830186835b87811015611763577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18a360301811261171557600080fd5b8901602081810191359067ffffffffffffffff82111561173457600080fd5b81360383131561174357600080fd5b61174e87838561161e565b965094850194939093019250506001016116b4565b50505073ffffffffffffffffffffffffffffffffffffffff841660208401529050949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261181f57600080fd5b83018035915067ffffffffffffffff82111561183a57600080fd5b60200191503681900382131561184f57600080fd5b9250929050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036118ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040815260006118c960408301858761161e565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b838152604060208083018290528282018490526000919085906060850184805b88811015611969578435611922816113cc565b73ffffffffffffffffffffffffffffffffffffffff1683528484013567ffffffffffffffff8116808214611954578384fd5b8486015250938501939185019160010161190f565b50909998505050505050505050565b80356020831015611249577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b6000602082840312156119c657600080fd5b815167ffffffffffffffff808211156119de57600080fd5b818401915084601f8301126119f257600080fd5b815181811115611a0457611a0461178c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611a4a57611a4a61178c565b81604052828152876020848701011115611a6357600080fd5b611a74836020830160208801611344565b97965050505050505056fea164736f6c6343000810000a", } var VerifierProxyABI = VerifierProxyMetaData.ABI diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt index a082c254c02..284e9886f3e 100644 --- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,9 +1,9 @@ GETH_VERSION: 1.12.0 errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier.bin a1b88979c6b0b210677346df554ffc33992d6ebe24be5a244475bfb4d153155e exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin bdae30fb942324e29ea99513fe1aadb705152bf5ac3dd411e8f31d24d99b7bc8 +fee_manager: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin 2c22cbfb24374f645eef8a368f30d1821e350501742118eebd0fa3e8bcbc4d29 llo_feeds: ../../../contracts/solc/v0.8.16/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager.bin cb71e018f67e49d7bc0e194c822204dfd59f79ff42e4fc8fd8ab63f3acd71361 llo_feeds_test: ../../../contracts/solc/v0.8.16/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 -reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin 87ff86cc1e15b9f291b6cdc8e1cc2d884f49d0555a03e1ab3da5bbfeaa0273fd +reward_manager: ../../../contracts/solc/v0.8.16/RewardManager.abi ../../../contracts/solc/v0.8.16/RewardManager.bin 8b163eb0537180accfa69beea298890f1605c8d9f776689ea26802eefda46457 verifier: ../../../contracts/solc/v0.8.16/Verifier.abi ../../../contracts/solc/v0.8.16/Verifier.bin 8f841ddd5e616fc1a8d6ac3d27ea9a383d958055237c90ecaf980f5cb3421e49 -verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin ffe46f650ac7e8389102596339fb060d5ca5b695efc462cae031dc1f102d2571 +verifier_proxy: ../../../contracts/solc/v0.8.16/VerifierProxy.abi ../../../contracts/solc/v0.8.16/VerifierProxy.bin 92ad0416e999e9d55e4f00a8b7df616bb69ae27ce52994a6061598e95364d2cc From da3e6116efda903c4a861788a290d7dc1e963773 Mon Sep 17 00:00:00 2001 From: Chris Cushman <104409744+vreff@users.noreply.github.com> Date: Wed, 6 Sep 2023 11:44:23 -0400 Subject: [PATCH 11/15] [VRF] opt out of snapshot checks (#10491) * [VRF] opt out of snapshot checks * Change VRF snapshot by 1 * Remove snapshot file --- .github/workflows/solidity-foundry.yml | 1 + contracts/gas-snapshots/vrf.gas-snapshot | 18 ------------------ 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 contracts/gas-snapshots/vrf.gas-snapshot diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index abdb64d1763..5044b668c2c 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -72,6 +72,7 @@ jobs: FOUNDRY_PROFILE: ${{ matrix.product }} - name: Run Forge snapshot + if: ${{ !contains(fromJson('["vrf"]'), matrix.product) }} run: | forge snapshot --check gas-snapshots/${{ matrix.product }}.gas-snapshot id: snapshot diff --git a/contracts/gas-snapshots/vrf.gas-snapshot b/contracts/gas-snapshots/vrf.gas-snapshot deleted file mode 100644 index 44145caadaa..00000000000 --- a/contracts/gas-snapshots/vrf.gas-snapshot +++ /dev/null @@ -1,18 +0,0 @@ -TrustedBlockhashStoreTest:testGenericBHSFunctions() (gas: 53507) -TrustedBlockhashStoreTest:testTrustedBHSFunctions() (gas: 54617) -VRFCoordinatorV2Plus_Migration:testDeregister() (gas: 101083) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenInvalidCaller() (gas: 33190) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenInvalidCoordinator() (gas: 19877) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenPendingFulfillment() (gas: 237679) -VRFCoordinatorV2Plus_Migration:testMigrateRevertsWhenReentrant() (gas: 357765) -VRFCoordinatorV2Plus_Migration:testMigration() (gas: 471605) -VRFCoordinatorV2Plus_Migration:testMigrationNoLink() (gas: 431075) -VRFV2Plus:testCancelSubWithNoLink() (gas: 160279) -VRFV2Plus:testCreateSubscription() (gas: 181127) -VRFV2Plus:testGetActiveSubscriptionIds() (gas: 3453681) -VRFV2Plus:testRegisterProvingKey() (gas: 101085) -VRFV2Plus:testRequestAndFulfillRandomWordsLINK() (gas: 755144) -VRFV2Plus:testRequestAndFulfillRandomWordsNative() (gas: 705591) -VRFV2Plus:testSetConfig() (gas: 73032) -VRFV2PlusWrapperTest:testRequestAndFulfillRandomWordsLINKWrapper() (gas: 393885) -VRFV2PlusWrapperTest:testRequestAndFulfillRandomWordsNativeWrapper() (gas: 294434) \ No newline at end of file From a53b972206cdfdb800c628b2296892e820c3eb85 Mon Sep 17 00:00:00 2001 From: krehermann Date: Wed, 6 Sep 2023 10:31:41 -0600 Subject: [PATCH 12/15] BCF-2564: take new loop relayer interface (#10430) * BCF-2564: take new loop relayer interface * take merged sha in relayer repo * fix solana --- core/chains/chain_kv_test.go | 2 +- core/chains/cosmos/chain.go | 4 - core/chains/cosmos/relay_extender.go | 85 -------- core/chains/cosmos/relayer_adapter.go | 51 +++++ core/chains/evm/mocks/chain.go | 14 -- core/chains/solana/chain.go | 4 +- core/chains/solana/relay_extender.go | 40 ---- core/chains/starknet/relay_extender.go | 43 ----- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../chainlink/relayer_chain_interoperators.go | 23 ++- core/services/chainlink/relayer_factory.go | 12 +- .../relay/evm/mocks/loop_relay_adapter.go | 181 +++++++----------- core/services/relay/evm/relayer_extender.go | 4 - core/web/solana_transfer_controller.go | 5 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- plugins/cmd/chainlink-solana/main.go | 4 +- plugins/cmd/chainlink-starknet/main.go | 4 +- 21 files changed, 160 insertions(+), 334 deletions(-) delete mode 100644 core/chains/cosmos/relay_extender.go create mode 100644 core/chains/cosmos/relayer_adapter.go delete mode 100644 core/chains/solana/relay_extender.go delete mode 100644 core/chains/starknet/relay_extender.go diff --git a/core/chains/chain_kv_test.go b/core/chains/chain_kv_test.go index e8b8f6c0ab4..f226b6f38be 100644 --- a/core/chains/chain_kv_test.go +++ b/core/chains/chain_kv_test.go @@ -94,7 +94,7 @@ func (s *testChainService) HealthReport() map[string]error { func (s *testChainService) GetChainStatus(ctx context.Context) (stat types.ChainStatus, err error) { return } -func (s *testChainService) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, err error) { +func (s *testChainService) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []types.NodeStatus, nextPageToken string, total int, err error) { return } diff --git a/core/chains/cosmos/chain.go b/core/chains/cosmos/chain.go index c73793c1c3a..48f4c2f8854 100644 --- a/core/chains/cosmos/chain.go +++ b/core/chains/cosmos/chain.go @@ -239,10 +239,6 @@ func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, return chains.ErrLOOPPUnsupported } -func (c *chain) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return c.Transact(ctx, from, to, amount, balanceCheck) -} - // TODO BCF-2602 statuses are static for non-evm chain and should be dynamic func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { stats := make([]relaytypes.NodeStatus, 0) diff --git a/core/chains/cosmos/relay_extender.go b/core/chains/cosmos/relay_extender.go deleted file mode 100644 index 3f9b9f5ad5b..00000000000 --- a/core/chains/cosmos/relay_extender.go +++ /dev/null @@ -1,85 +0,0 @@ -package cosmos - -import ( - "context" - "fmt" - "math/big" - - "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" - - "github.com/smartcontractkit/chainlink-relay/pkg/loop" - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - - pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" - "github.com/smartcontractkit/chainlink/v2/core/chains" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// LegacyChainContainer is container interface for Cosmos chains -type LegacyChainContainer interface { - Get(id string) (adapters.Chain, error) - Len() int - List(ids ...string) ([]adapters.Chain, error) - Slice() []adapters.Chain -} - -type LegacyChains = chains.ChainsKV[adapters.Chain] - -var _ LegacyChainContainer = &LegacyChains{} - -func NewLegacyChains(m map[string]adapters.Chain) *LegacyChains { - return chains.NewChainsKV[adapters.Chain](m) -} - -type LoopRelayerChainer interface { - loop.Relayer - Chain() adapters.Chain -} - -type LoopRelayerChain struct { - loop.Relayer - chain adapters.Chain -} - -func NewLoopRelayerChain(r *pkgcosmos.Relayer, s *RelayExtender) *LoopRelayerChain { - - ra := relay.NewRelayerAdapter(r, s) - return &LoopRelayerChain{ - Relayer: ra, - chain: s, - } -} -func (r *LoopRelayerChain) Chain() adapters.Chain { - return r.chain -} - -var _ LoopRelayerChainer = &LoopRelayerChain{} - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - adapters.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *CosmosConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: cosmos relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported -} diff --git a/core/chains/cosmos/relayer_adapter.go b/core/chains/cosmos/relayer_adapter.go new file mode 100644 index 00000000000..899eae01951 --- /dev/null +++ b/core/chains/cosmos/relayer_adapter.go @@ -0,0 +1,51 @@ +package cosmos + +import ( + "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/adapters" + + "github.com/smartcontractkit/chainlink-relay/pkg/loop" + + pkgcosmos "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" + "github.com/smartcontractkit/chainlink/v2/core/chains" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" +) + +// LegacyChainContainer is container interface for Cosmos chains +type LegacyChainContainer interface { + Get(id string) (adapters.Chain, error) + Len() int + List(ids ...string) ([]adapters.Chain, error) + Slice() []adapters.Chain +} + +type LegacyChains = chains.ChainsKV[adapters.Chain] + +var _ LegacyChainContainer = &LegacyChains{} + +func NewLegacyChains(m map[string]adapters.Chain) *LegacyChains { + return chains.NewChainsKV[adapters.Chain](m) +} + +type LoopRelayerChainer interface { + loop.Relayer + Chain() adapters.Chain +} + +type LoopRelayerChain struct { + loop.Relayer + chain adapters.Chain +} + +func NewLoopRelayerChain(r *pkgcosmos.Relayer, s adapters.Chain) *LoopRelayerChain { + + ra := relay.NewRelayerAdapter(r, s) + return &LoopRelayerChain{ + Relayer: ra, + chain: s, + } +} +func (r *LoopRelayerChain) Chain() adapters.Chain { + return r.chain +} + +var _ LoopRelayerChainer = &LoopRelayerChain{} diff --git a/core/chains/evm/mocks/chain.go b/core/chains/evm/mocks/chain.go index 92d39a95fb9..bf4d1581e22 100644 --- a/core/chains/evm/mocks/chain.go +++ b/core/chains/evm/mocks/chain.go @@ -320,20 +320,6 @@ func (_m *Chain) Ready() error { return r0 } -// SendTx provides a mock function with given fields: ctx, from, to, amount, balanceCheck -func (_m *Chain) SendTx(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { - ret := _m.Called(ctx, from, to, amount, balanceCheck) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { - r0 = rf(ctx, from, to, amount, balanceCheck) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // Start provides a mock function with given fields: _a0 func (_m *Chain) Start(_a0 context.Context) error { ret := _m.Called(_a0) diff --git a/core/chains/solana/chain.go b/core/chains/solana/chain.go index 5678cc7f504..b39435368ad 100644 --- a/core/chains/solana/chain.go +++ b/core/chains/solana/chain.go @@ -248,7 +248,7 @@ func (c *chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken } func (c *chain) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - panic("unimplmented") + return c.sendTx(ctx, from, to, amount, balanceCheck) } func (c *chain) listNodeStatuses(start, end int) ([]relaytypes.NodeStatus, int, error) { @@ -392,7 +392,7 @@ func (c *chain) HealthReport() map[string]error { return report } -func (c *chain) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { +func (c *chain) sendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { reader, err := c.Reader() if err != nil { return fmt.Errorf("chain unreachable: %w", err) diff --git a/core/chains/solana/relay_extender.go b/core/chains/solana/relay_extender.go deleted file mode 100644 index e25cce0b697..00000000000 --- a/core/chains/solana/relay_extender.go +++ /dev/null @@ -1,40 +0,0 @@ -package solana - -import ( - "context" - "fmt" - "math/big" - - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - "github.com/smartcontractkit/chainlink-solana/pkg/solana" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - solana.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *SolanaConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: cosmos relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return r.chainImpl.SendTx(ctx, from, to, amount, balanceCheck) -} diff --git a/core/chains/starknet/relay_extender.go b/core/chains/starknet/relay_extender.go deleted file mode 100644 index 54d5ab2ab03..00000000000 --- a/core/chains/starknet/relay_extender.go +++ /dev/null @@ -1,43 +0,0 @@ -package starknet - -import ( - "context" - "fmt" - "math/big" - - relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types" - starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain" - - "github.com/smartcontractkit/chainlink/v2/core/chains" - - "github.com/smartcontractkit/chainlink/v2/core/services/relay" -) - -// TODO remove these wrappers after BCF-2441 -type RelayExtender struct { - starkchain.Chain - chainImpl *chain -} - -var _ relay.RelayerExt = &RelayExtender{} - -func NewRelayExtender(cfg *StarknetConfig, opts ChainOpts) (*RelayExtender, error) { - c, err := NewChain(cfg, opts) - if err != nil { - return nil, err - } - chainImpl, ok := (c).(*chain) - if !ok { - return nil, fmt.Errorf("internal error: starkent relay extender got wrong type %t", c) - } - return &RelayExtender{Chain: chainImpl, chainImpl: chainImpl}, nil -} -func (r *RelayExtender) GetChainStatus(ctx context.Context) (relaytypes.ChainStatus, error) { - return r.chainImpl.GetChainStatus(ctx) -} -func (r *RelayExtender) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) (stats []relaytypes.NodeStatus, nextPageToken string, total int, err error) { - return r.chainImpl.ListNodeStatuses(ctx, pageSize, pageToken) -} -func (r *RelayExtender) Transact(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return chains.ErrLOOPPUnsupported -} diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 738d21ddb73..05c80a63dbc 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -299,7 +299,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230829114801-14bf715f805e // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 9d919d1ac72..61b13f05a10 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1377,8 +1377,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 65859338b6c..924279389f0 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -215,10 +215,8 @@ func (rs *CoreRelayerChainInteroperators) ChainStatus(ctx context.Context, id re if err != nil { return types.ChainStatus{}, fmt.Errorf("%w: error getting chain status: %w", chains.ErrNotFound, err) } - // this call is weird because the [loop.Relayer] interface still requires id - // but in this context the `relayer` should only have only id - // moreover, the `relayer` here is pinned to one chain we need to pass the chain id - return lr.ChainStatus(ctx, id.ChainID.String()) + + return lr.GetChainStatus(ctx) } func (rs *CoreRelayerChainInteroperators) ChainStatuses(ctx context.Context, offset, limit int) ([]types.ChainStatus, int, error) { @@ -240,8 +238,7 @@ func (rs *CoreRelayerChainInteroperators) ChainStatuses(ctx context.Context, off }) for _, rid := range relayerIds { lr := rs.loopRelayers[rid] - // the relayer is chain specific; use the chain id and not the relayer id - stat, err := lr.ChainStatus(ctx, rid.ChainID.String()) + stat, err := lr.GetChainStatus(ctx) if err != nil { totalErr = errors.Join(totalErr, err) continue @@ -275,7 +272,7 @@ func (rs *CoreRelayerChainInteroperators) Node(ctx context.Context, name string) } // ids must be a string representation of relay.Identifier -// ids are a filter; if none are specificied, all are returned. +// ids are a filter; if none are specified, all are returned. // TODO: BCF-2440/1 this signature can be changed to id relay.Identifier which is a much better API func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offset, limit int, relayerIDs ...string) (nodes []types.NodeStatus, count int, err error) { var ( @@ -283,13 +280,14 @@ func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offs result []types.NodeStatus ) if len(relayerIDs) == 0 { - for rid, lr := range rs.loopRelayers { - stats, _, err := lr.NodeStatuses(ctx, offset, limit, rid.ChainID.String()) + for _, lr := range rs.loopRelayers { + stats, _, total, err := lr.ListNodeStatuses(ctx, int32(limit), "") if err != nil { totalErr = errors.Join(totalErr, err) continue } result = append(result, stats...) + count += total } } else { for _, idStr := range relayerIDs { @@ -304,22 +302,23 @@ func (rs *CoreRelayerChainInteroperators) NodeStatuses(ctx context.Context, offs totalErr = errors.Join(totalErr, fmt.Errorf("relayer %s does not exist", rid.Name())) continue } - nodeStats, _, err := lr.NodeStatuses(ctx, offset, limit, rid.ChainID.String()) + nodeStats, _, total, err := lr.ListNodeStatuses(ctx, int32(limit), "") if err != nil { totalErr = errors.Join(totalErr, err) continue } result = append(result, nodeStats...) + count += total } } if totalErr != nil { return nil, 0, totalErr } if len(result) > limit && limit > 0 { - return result[offset : offset+limit], limit, nil + return result[offset : offset+limit], count, nil } - return result[offset:], len(result[offset:]), nil + return result[offset:], count, nil } type FilterFn func(id relay.ID) bool diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 4ff70a585ac..6c09f5c4ab4 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -131,11 +131,11 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.SolanaCo Configs: solana.NewConfigs(singleChainCfg), } - relayExt, err := solana.NewRelayExtender(chainCfg, opts) + chain, err := solana.NewChain(chainCfg, opts) if err != nil { return nil, err } - solanaRelayers[relayId] = relay.NewRelayerAdapter(pkgsolana.NewRelayer(solLggr, relayExt), relayExt) + solanaRelayers[relayId] = relay.NewRelayerAdapter(pkgsolana.NewRelayer(solLggr, chain), chain) } } return solanaRelayers, nil @@ -203,12 +203,12 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starknet.St Configs: starknet.NewConfigs(singleChainCfg), } - relayExt, err := starknet.NewRelayExtender(chainCfg, opts) + chain, err := starknet.NewChain(chainCfg, opts) if err != nil { return nil, err } - starknetRelayers[relayId] = relay.NewRelayerAdapter(pkgstarknet.NewRelayer(starkLggr, relayExt), relayExt) + starknetRelayers[relayId] = relay.NewRelayerAdapter(pkgstarknet.NewRelayer(starkLggr, chain), chain) } } return starknetRelayers, nil @@ -241,13 +241,13 @@ func (r *RelayerFactory) NewCosmos(ctx context.Context, config CosmosFactoryConf EventBroadcaster: config.EventBroadcaster, } opts.Configs = cosmos.NewConfigs(cosmos.CosmosConfigs{chainCfg}) - relayExt, err := cosmos.NewRelayExtender(chainCfg, opts) + chain, err := cosmos.NewChain(chainCfg, opts) if err != nil { return nil, fmt.Errorf("failed to load Cosmos chain %q: %w", relayId, err) } - relayers[relayId] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, relayExt), relayExt) + relayers[relayId] = cosmos.NewLoopRelayerChain(pkgcosmos.NewRelayer(lggr, chain), chain) } return relayers, nil diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index b0d9b7cf95e..7ed28ac4b11 100644 --- a/core/services/relay/evm/mocks/loop_relay_adapter.go +++ b/core/services/relay/evm/mocks/loop_relay_adapter.go @@ -33,63 +33,6 @@ func (_m *LoopRelayAdapter) Chain() evm.Chain { return r0 } -// ChainStatus provides a mock function with given fields: ctx, id -func (_m *LoopRelayAdapter) ChainStatus(ctx context.Context, id string) (types.ChainStatus, error) { - ret := _m.Called(ctx, id) - - var r0 types.ChainStatus - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (types.ChainStatus, error)); ok { - return rf(ctx, id) - } - if rf, ok := ret.Get(0).(func(context.Context, string) types.ChainStatus); ok { - r0 = rf(ctx, id) - } else { - r0 = ret.Get(0).(types.ChainStatus) - } - - if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { - r1 = rf(ctx, id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ChainStatuses provides a mock function with given fields: ctx, offset, limit -func (_m *LoopRelayAdapter) ChainStatuses(ctx context.Context, offset int, limit int) ([]types.ChainStatus, int, error) { - ret := _m.Called(ctx, offset, limit) - - var r0 []types.ChainStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int) ([]types.ChainStatus, int, error)); ok { - return rf(ctx, offset, limit) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int) []types.ChainStatus); ok { - r0 = rf(ctx, offset, limit) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.ChainStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int) int); ok { - r1 = rf(ctx, offset, limit) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int) error); ok { - r2 = rf(ctx, offset, limit) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // Close provides a mock function with given fields: func (_m *LoopRelayAdapter) Close() error { ret := _m.Called() @@ -118,6 +61,30 @@ func (_m *LoopRelayAdapter) Default() bool { return r0 } +// GetChainStatus provides a mock function with given fields: ctx +func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { + ret := _m.Called(ctx) + + var r0 types.ChainStatus + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) types.ChainStatus); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(types.ChainStatus) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HealthReport provides a mock function with given fields: func (_m *LoopRelayAdapter) HealthReport() map[string]error { ret := _m.Called() @@ -134,6 +101,46 @@ func (_m *LoopRelayAdapter) HealthReport() map[string]error { return r0 } +// ListNodeStatuses provides a mock function with given fields: ctx, pageSize, pageToken +func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { + ret := _m.Called(ctx, pageSize, pageToken) + + var r0 []types.NodeStatus + var r1 string + var r2 int + var r3 error + if rf, ok := ret.Get(0).(func(context.Context, int32, string) ([]types.NodeStatus, string, int, error)); ok { + return rf(ctx, pageSize, pageToken) + } + if rf, ok := ret.Get(0).(func(context.Context, int32, string) []types.NodeStatus); ok { + r0 = rf(ctx, pageSize, pageToken) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.NodeStatus) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int32, string) string); ok { + r1 = rf(ctx, pageSize, pageToken) + } else { + r1 = ret.Get(1).(string) + } + + if rf, ok := ret.Get(2).(func(context.Context, int32, string) int); ok { + r2 = rf(ctx, pageSize, pageToken) + } else { + r2 = ret.Get(2).(int) + } + + if rf, ok := ret.Get(3).(func(context.Context, int32, string) error); ok { + r3 = rf(ctx, pageSize, pageToken) + } else { + r3 = ret.Error(3) + } + + return r0, r1, r2, r3 +} + // Name provides a mock function with given fields: func (_m *LoopRelayAdapter) Name() string { ret := _m.Called() @@ -252,46 +259,6 @@ func (_m *LoopRelayAdapter) NewMercuryProvider(_a0 context.Context, _a1 types.Re return r0, r1 } -// NodeStatuses provides a mock function with given fields: ctx, offset, limit, chainIDs -func (_m *LoopRelayAdapter) NodeStatuses(ctx context.Context, offset int, limit int, chainIDs ...string) ([]types.NodeStatus, int, error) { - _va := make([]interface{}, len(chainIDs)) - for _i := range chainIDs { - _va[_i] = chainIDs[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx, offset, limit) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - var r0 []types.NodeStatus - var r1 int - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) ([]types.NodeStatus, int, error)); ok { - return rf(ctx, offset, limit, chainIDs...) - } - if rf, ok := ret.Get(0).(func(context.Context, int, int, ...string) []types.NodeStatus); ok { - r0 = rf(ctx, offset, limit, chainIDs...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.NodeStatus) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int, int, ...string) int); ok { - r1 = rf(ctx, offset, limit, chainIDs...) - } else { - r1 = ret.Get(1).(int) - } - - if rf, ok := ret.Get(2).(func(context.Context, int, int, ...string) error); ok { - r2 = rf(ctx, offset, limit, chainIDs...) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - // Ready provides a mock function with given fields: func (_m *LoopRelayAdapter) Ready() error { ret := _m.Called() @@ -306,13 +273,13 @@ func (_m *LoopRelayAdapter) Ready() error { return r0 } -// SendTx provides a mock function with given fields: ctx, chainID, from, to, amount, balanceCheck -func (_m *LoopRelayAdapter) SendTx(ctx context.Context, chainID string, from string, to string, amount *big.Int, balanceCheck bool) error { - ret := _m.Called(ctx, chainID, from, to, amount, balanceCheck) +// Start provides a mock function with given fields: _a0 +func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { + ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *big.Int, bool) error); ok { - r0 = rf(ctx, chainID, from, to, amount, balanceCheck) + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) } else { r0 = ret.Error(0) } @@ -320,13 +287,13 @@ func (_m *LoopRelayAdapter) SendTx(ctx context.Context, chainID string, from str return r0 } -// Start provides a mock function with given fields: _a0 -func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { - ret := _m.Called(_a0) +// Transact provides a mock function with given fields: ctx, from, to, amount, balanceCheck +func (_m *LoopRelayAdapter) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { + ret := _m.Called(ctx, from, to, amount, balanceCheck) var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) + if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { + r0 = rf(ctx, from, to, amount, balanceCheck) } else { r0 = ret.Error(0) } diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 5b3a3535c51..637baedab83 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -139,10 +139,6 @@ var ErrInconsistentChainRelayerExtender = errors.New("inconsistent evm chain rel // Legacy interface remove after BFC-2441, BCF-2564 -func (s *ChainRelayerExt) SendTx(ctx context.Context, from, to string, amount *big.Int, balanceCheck bool) error { - return s.Transact(ctx, from, to, amount, balanceCheck) -} - func (s *ChainRelayerExt) ChainStatus(ctx context.Context, id string) (relaytypes.ChainStatus, error) { if s.chain.ID().String() != id { return relaytypes.ChainStatus{}, fmt.Errorf("%w: given id %q does not match expected id %q", ErrInconsistentChainRelayerExtender, id, s.chain.ID()) diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index 5f92c02269b..df750586a46 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -58,9 +58,8 @@ func (tc *SolanaTransfersController) Create(c *gin.Context) { jsonAPIError(c, http.StatusInternalServerError, err) return } - // note the [loop.Relayer] API is in intermediate state. we found the relayer above; we should not need to pass - // the chain id here - err = relayer.SendTx(c, tr.SolanaChainID, tr.From.String(), tr.To.String(), amount, !tr.AllowHigherAmounts) + + err = relayer.Transact(c, tr.From.String(), tr.To.String(), amount, !tr.AllowHigherAmounts) if err != nil { switch err { case chains.ErrNotFound, chains.ErrChainIDEmpty: diff --git a/go.mod b/go.mod index 730a30daa16..56c59625339 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 github.com/smartcontractkit/libocr v0.0.0-20230816220705-665e93233ae5 diff --git a/go.sum b/go.sum index 152a27cad3e..8d127373678 100644 --- a/go.sum +++ b/go.sum @@ -1377,8 +1377,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 h1:DojChlaudA1HAxwQPKmt/EDf36OUeFJ0LJBYClauMyU= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index c7e8ec794a2..0874c743853 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -384,7 +384,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 // indirect github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index d43c4163142..c3a08560bda 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2252,8 +2252,8 @@ github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af6899451 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20230831132059-42af68994512/go.mod h1:xMwqRdj5vqYhCJXgKVqvyAwdcqM6ZAEhnwEQ4Khsop8= github.com/smartcontractkit/chainlink-env v0.36.0 h1:CFOjs0c0y3lrHi/fl5qseCH9EQa5W/6CFyOvmhe2VnA= github.com/smartcontractkit/chainlink-env v0.36.0/go.mod h1:NbRExHmJGnKSYXmvNuJx5VErSx26GtE1AEN/CRzYOg8= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938 h1:LnxS4RoDcUS4+zXoY/gaV4BB6u90DgW3LtyFCoCpJzY= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230901143551-bf6bd84d6938/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4 h1:yArUq/0t126bl8BRtjLCf2NuHK35CDIkhc3M5P46apc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230905185157-da01915913a4/go.mod h1:gWclxGW7rLkbjXn7FGizYlyKhp/boekto4MEYGyiMG4= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca h1:x7M0m512gtXw5Z4B1WJPZ52VgshoIv+IvHqQ8hsH4AE= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca/go.mod h1:RIUJXn7EVp24TL2p4FW79dYjyno23x5mjt1nKN+5WEk= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 h1:ByVauKFXphRlSNG47lNuxZ9aicu+r8AoNp933VRPpCw= diff --git a/plugins/cmd/chainlink-solana/main.go b/plugins/cmd/chainlink-solana/main.go index 150a9d840dd..9f470355297 100644 --- a/plugins/cmd/chainlink-solana/main.go +++ b/plugins/cmd/chainlink-solana/main.go @@ -71,11 +71,11 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, keystore KeyStore: keystore, Configs: solana.NewConfigs(cfgAdapter), } - relayExt, err := solana.NewRelayExtender(&cfg.Solana, opts) + chain, err := solana.NewChain(&cfg.Solana, opts) if err != nil { return nil, fmt.Errorf("failed to create chain: %w", err) } - ra := relay.NewRelayerAdapter(pkgsol.NewRelayer(c.Logger, relayExt), relayExt) + ra := relay.NewRelayerAdapter(pkgsol.NewRelayer(c.Logger, chain), chain) c.SubService(ra) diff --git a/plugins/cmd/chainlink-starknet/main.go b/plugins/cmd/chainlink-starknet/main.go index 15bd0122121..433d4408e31 100644 --- a/plugins/cmd/chainlink-starknet/main.go +++ b/plugins/cmd/chainlink-starknet/main.go @@ -75,11 +75,11 @@ func (c *pluginRelayer) NewRelayer(ctx context.Context, config string, loopKs lo Configs: starknet.NewConfigs(cfgAdapter), } - relayExt, err := starknet.NewRelayExtender(&cfg.Starknet, opts) + chain, err := starknet.NewChain(&cfg.Starknet, opts) if err != nil { return nil, fmt.Errorf("failed to create chain: %w", err) } - ra := relay.NewRelayerAdapter(pkgstarknet.NewRelayer(c.Logger, relayExt), relayExt) + ra := relay.NewRelayerAdapter(pkgstarknet.NewRelayer(c.Logger, chain), chain) c.SubService(ra) From b5e6207e1166520c1965ffa30f9d148e715f1e16 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 6 Sep 2023 11:52:25 -0500 Subject: [PATCH 13/15] golangci-lint tweaks (#10510) --- GNUmakefile | 2 +- core/services/vrf/v2/integration_v2_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 8b6fd2d2ac4..8698d845f3d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -146,7 +146,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%s).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt GORELEASER_CONFIG ?= .goreleaser.yaml diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index 3609754df3d..3b85a524bac 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -2143,7 +2143,7 @@ VALUES (:nonce, :from_address, :to_address, :encoded_payload, :value, :gas_limit dbAttempt := txmgr.DbEthTxAttemptFromEthTxAttempt(&attempt) //nolint:gosec - just copying fields _, err = db.NamedExec(sql, &dbAttempt) require.NoError(t, err) - txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolin:gosec - just copying fields + txmgr.DbEthTxAttemptToEthTxAttempt(dbAttempt, &attempt) //nolint:gosec - just copying fields } // add eth_receipts From a15bcd805bcfba930f3abdbf906db3ff04519ac5 Mon Sep 17 00:00:00 2001 From: Chris Cushman <104409744+vreff@users.noreply.github.com> Date: Wed, 6 Sep 2023 13:50:43 -0400 Subject: [PATCH 14/15] [Automation] Update docker scripts (#10516) --- core/scripts/chaincli/command/keeper/launch.go | 2 +- core/scripts/chaincli/handler/keeper_verifiable_load.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/scripts/chaincli/command/keeper/launch.go b/core/scripts/chaincli/command/keeper/launch.go index 7e4c79f70d2..e918095edb4 100644 --- a/core/scripts/chaincli/command/keeper/launch.go +++ b/core/scripts/chaincli/command/keeper/launch.go @@ -47,7 +47,7 @@ var launchAndTestCmd = &cobra.Command{ func init() { launchAndTestCmd.Flags().BoolP("withdraw", "w", true, "Specify if funds should be withdrawn and upkeeps should be canceled") - launchAndTestCmd.Flags().BoolP("bootstrap", "b", true, "Specify if launching bootstrap node is required. Default listen ports(5688, 8000) are used, if you need to use custom ports, please use bootstrap command") + launchAndTestCmd.Flags().BoolP("bootstrap", "b", false, "Specify if launching bootstrap node is required. Default listen ports(5688, 8000) are used, if you need to use custom ports, please use bootstrap command") launchAndTestCmd.Flags().BoolP("export-logs", "l", false, "Specify if container logs should be exported to ./") launchAndTestCmd.Flags().BoolP("force", "f", false, "Specify if existing containers should be forcefully removed ./") } diff --git a/core/scripts/chaincli/handler/keeper_verifiable_load.go b/core/scripts/chaincli/handler/keeper_verifiable_load.go index ad704393877..429a7620079 100644 --- a/core/scripts/chaincli/handler/keeper_verifiable_load.go +++ b/core/scripts/chaincli/handler/keeper_verifiable_load.go @@ -37,7 +37,7 @@ type upkeepInfo struct { } type verifiableLoad interface { - GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) + GetAllActiveUpkeepIDsOnRegistry(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) Counters(opts *bind.CallOpts, upkeepId *big.Int) (*big.Int, error) GetBucketedDelays(opts *bind.CallOpts, upkeepId *big.Int, bucket uint16) ([]*big.Int, error) Buckets(opts *bind.CallOpts, arg0 *big.Int) (uint16, error) @@ -79,7 +79,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context) { } // get all active upkeep IDs on this verifiable load contract - upkeepIds, err := v.GetActiveUpkeepIDs(opts, big.NewInt(0), big.NewInt(0)) + upkeepIds, err := v.GetAllActiveUpkeepIDsOnRegistry(opts, big.NewInt(0), big.NewInt(0)) if err != nil { log.Fatalf("failed to get active upkeep IDs from %s: %v", k.cfg.VerifiableLoadContractAddress, err) } From ad22c6ed0c4bed4053adc1585dca0ad55b481685 Mon Sep 17 00:00:00 2001 From: Amir Y <83904651+amirylm@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:17:23 +0300 Subject: [PATCH 15/15] Seed order to manage logs overflow (#10485) * update ocr2keepers * go mod tidy * buffer: drop logs by seed-order * comment out noisy log * ensure order for provider.GetLatestPayloads() * ensure order for recoverer.GetRecoveryProposals() * use a normalized value of latestBlock * set overall limit for recovery proposals (MaxProposals) value TBD, currently set to 50 * set max proposals to 20 (was 50) * apply total limits when dequeing for payloads MaxPayloads was set to 100 * fix test * fix max block logs * protect log spamming * renaming * lint * set offset to 100 * added tests * use maps when sorting * temporary added blockhash to log id * lint * remove todo from log id func --- .../ocr2keeper/evm21/logprovider/buffer.go | 132 ++++- .../evm21/logprovider/buffer_test.go | 510 +++++++++++++++++- .../evm21/logprovider/integration_test.go | 6 +- .../ocr2keeper/evm21/logprovider/provider.go | 11 +- .../ocr2keeper/evm21/logprovider/recoverer.go | 55 +- .../evm21/logprovider/recoverer_test.go | 4 +- .../ocr2/plugins/ocr2keeper/evm21/registry.go | 1 + 7 files changed, 677 insertions(+), 42 deletions(-) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go index ad0ae5e1024..1835ac69f09 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer.go @@ -1,26 +1,45 @@ package logprovider import ( + "encoding/hex" "math/big" "sort" "sync" "sync/atomic" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" ) var ( - // allowedLogsPerBlock is the maximum number of logs allowed per upkeep in a block. - allowedLogsPerBlock = 128 - // bufferMaxBlockSize is the maximum number of blocks in the buffer. - bufferMaxBlockSize = 1024 + // maxLogsPerUpkeepInBlock is the maximum number of logs allowed per upkeep in a block. + maxLogsPerUpkeepInBlock = 32 + // maxLogsPerBlock is the maximum number of blocks in the buffer. + maxLogsPerBlock = 1024 ) // fetchedLog holds the log and the ID of the upkeep type fetchedLog struct { upkeepID *big.Int log logpoller.Log + // cachedLogID is the cached log identifier, used for sorting. + // It is calculated lazily, and cached for performance. + cachedLogID string +} + +func (l *fetchedLog) getLogID() string { + if len(l.cachedLogID) == 0 { + ext := ocr2keepers.LogTriggerExtension{ + Index: uint32(l.log.LogIndex), + } + copy(ext.TxHash[:], l.log.TxHash[:]) + copy(ext.BlockHash[:], l.log.BlockHash[:]) + l.cachedLogID = hex.EncodeToString(ext.LogIdentifier()) + } + return l.cachedLogID } // fetchedBlock holds the logs fetched for a block @@ -33,9 +52,46 @@ type fetchedBlock struct { visited []fetchedLog } +func (b *fetchedBlock) Append(lggr logger.Logger, fl fetchedLog, maxBlockLogs, maxUpkeepLogs int) (fetchedLog, bool) { + has, upkeepLogs := b.has(fl.upkeepID, fl.log) + if has { + // Skipping known logs + return fetchedLog{}, false + } + // lggr.Debugw("Adding log", "i", i, "blockBlock", currentBlock.blockNumber, "logBlock", log.BlockNumber, "id", id) + b.logs = append(b.logs, fl) + + // drop logs if we reached limits. + if upkeepLogs+1 > maxUpkeepLogs { + // in case we have logs overflow for a particular upkeep, we drop a log of that upkeep, + // based on shared, random (per block) order of the logs in the block. + b.Sort() + var dropped fetchedLog + currentLogs := make([]fetchedLog, 0, len(b.logs)-1) + for _, l := range b.logs { + if dropped.upkeepID == nil && l.upkeepID.Cmp(fl.upkeepID) == 0 { + dropped = l + continue + } + currentLogs = append(currentLogs, l) + } + b.logs = currentLogs + return dropped, true + } else if len(b.logs)+len(b.visited) > maxBlockLogs { + // in case we have logs overflow in the buffer level, we drop a log based on + // shared, random (per block) order of the logs in the block. + b.Sort() + dropped := b.logs[0] + b.logs = b.logs[1:] + return dropped, true + } + + return fetchedLog{}, true +} + // Has returns true if the block has the log, // and the number of logs for that upkeep in the block. -func (b fetchedBlock) Has(id *big.Int, log logpoller.Log) (bool, int) { +func (b fetchedBlock) has(id *big.Int, log logpoller.Log) (bool, int) { allLogs := append(b.logs, b.visited...) upkeepLogs := 0 for _, l := range allLogs { @@ -62,6 +118,22 @@ func (b fetchedBlock) Clone() fetchedBlock { } } +// Sort by log identifiers, shuffled using a pseduorandom souce that is shared across all nodes +// for a given block. +func (b *fetchedBlock) Sort() { + randSeed := random.GetRandomKeySource(nil, uint64(b.blockNumber)) + + shuffledLogIDs := make(map[string]string, len(b.logs)) + for _, log := range b.logs { + logID := log.getLogID() + shuffledLogIDs[logID] = random.ShuffleString(logID, randSeed) + } + + sort.SliceStable(b.logs, func(i, j int) bool { + return shuffledLogIDs[b.logs[i].getLogID()] < shuffledLogIDs[b.logs[j].getLogID()] + }) +} + // logEventBuffer is a circular/ring buffer of fetched logs. // Each entry in the buffer represents a block, // and holds the logs fetched for that block. @@ -97,6 +169,7 @@ func (b *logEventBuffer) bufferSize() int { } // enqueue adds logs (if not exist) to the buffer, returning the number of logs added +// minus the number of logs dropped. func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { b.lock.Lock() defer b.lock.Unlock() @@ -107,7 +180,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { maxUpkeepLogs := int(b.maxUpkeepLogsPerBlock) latestBlock := b.latestBlockSeen() - added := 0 + added, dropped := 0, 0 + for _, log := range logs { if log.BlockNumber == 0 { // invalid log @@ -125,23 +199,20 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { lggr.Debugw("Skipping log from old block", "currentBlock", currentBlock.blockNumber, "newBlock", log.BlockNumber) continue } - if len(currentBlock.logs)+1 > maxBlockLogs { - lggr.Debugw("Reached max logs number per block, dropping log", "blockNumber", log.BlockNumber, - "blockHash", log.BlockHash, "txHash", log.TxHash, "logIndex", log.LogIndex) + droppedLog, ok := currentBlock.Append(lggr, fetchedLog{upkeepID: id, log: log}, maxBlockLogs, maxUpkeepLogs) + if !ok { + // Skipping known logs continue } - if has, upkeepLogs := currentBlock.Has(id, log); has { - // Skipping existing log - continue - } else if upkeepLogs+1 > maxUpkeepLogs { - lggr.Debugw("Reached max logs number per upkeep, dropping log", "blockNumber", log.BlockNumber, - "blockHash", log.BlockHash, "txHash", log.TxHash, "logIndex", log.LogIndex) - continue + if droppedLog.upkeepID != nil { + dropped++ + lggr.Debugw("Reached log buffer limits, dropping log", "blockNumber", droppedLog.log.BlockNumber, + "blockHash", droppedLog.log.BlockHash, "txHash", droppedLog.log.TxHash, "logIndex", droppedLog.log.LogIndex, + "upkeepID", droppedLog.upkeepID.String()) } - // lggr.Debugw("Adding log", "i", i, "blockBlock", currentBlock.blockNumber, "logBlock", log.BlockNumber, "id", id) - currentBlock.logs = append(currentBlock.logs, fetchedLog{upkeepID: id, log: log}) - b.blocks[i] = currentBlock added++ + b.blocks[i] = currentBlock + if log.BlockNumber > latestBlock { latestBlock = log.BlockNumber } @@ -151,10 +222,10 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { atomic.StoreInt64(&b.latestBlock, latestBlock) } if added > 0 { - lggr.Debugw("Added logs to buffer", "addedLogs", added, "latestBlock", latestBlock) + lggr.Debugw("Added logs to buffer", "addedLogs", added, "dropped", dropped, "latestBlock", latestBlock) } - return added + return added - dropped } // peek returns the logs in range [latestBlock-blocks, latestBlock] @@ -196,7 +267,7 @@ func (b *logEventBuffer) peekRange(start, end int64) []fetchedLog { } // dequeueRange returns the logs between start and end inclusive. -func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit int) []fetchedLog { +func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit, totalLimit int) []fetchedLog { b.lock.Lock() defer b.lock.Unlock() @@ -214,20 +285,33 @@ func (b *logEventBuffer) dequeueRange(start, end int64, upkeepLimit int) []fetch }) logsCount := map[string]int{} + totalCount := 0 var results []fetchedLog for _, block := range fetchedBlocks { - // double checking that we don't have any gaps in the range if block.blockNumber < start || block.blockNumber > end { + // double checking that we don't have any gaps in the range continue } + if totalCount >= totalLimit { + // reached total limit, no need to process more blocks + break + } + // Sort the logs in random order that is shared across all nodes. + // This ensures that nodes across the network will process the same logs. + block.Sort() var remainingLogs, blockResults []fetchedLog for _, log := range block.logs { + if totalCount >= totalLimit { + remainingLogs = append(remainingLogs, log) + continue + } if logsCount[log.upkeepID.String()] >= upkeepLimit { remainingLogs = append(remainingLogs, log) continue } - logsCount[log.upkeepID.String()]++ blockResults = append(blockResults, log) + logsCount[log.upkeepID.String()]++ + totalCount++ } if len(blockResults) == 0 { continue diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go index 18eecb748a5..0f389d0d418 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/buffer_test.go @@ -1,15 +1,18 @@ package logprovider import ( + "encoding/hex" "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" + ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evm21/core" ) func TestLogEventBuffer_GetBlocksInRange(t *testing.T) { @@ -236,7 +239,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { results := buf.peekRange(int64(1), int64(2)) require.Equal(t, 2, len(results)) verifyBlockNumbers(t, results, 1, 2) - removed := buf.dequeueRange(int64(1), int64(2), 2) + removed := buf.dequeueRange(int64(1), int64(2), 2, 10) require.Equal(t, 2, len(removed)) results = buf.peekRange(int64(1), int64(2)) require.Equal(t, 0, len(results)) @@ -256,7 +259,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { results := buf.peek(8) require.Equal(t, 4, len(results)) verifyBlockNumbers(t, results, 1, 2, 3, 3) - removed := buf.dequeueRange(1, 3, 5) + removed := buf.dequeueRange(1, 3, 5, 5) require.Equal(t, 4, len(removed)) buf.lock.Lock() require.Equal(t, 0, len(buf.blocks[0].logs)) @@ -313,10 +316,18 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { logpoller.Log{BlockNumber: 5, TxHash: common.HexToHash("0x5"), LogIndex: 0}, ), 5) - logs := buf.dequeueRange(1, 5, 2) + logs := buf.dequeueRange(1, 5, 2, 10) require.Equal(t, 2, len(logs)) require.Equal(t, int64(5), logs[0].log.BlockNumber) require.Equal(t, int64(4), logs[1].log.BlockNumber) + + require.Equal(t, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 4, TxHash: common.HexToHash("0x4"), LogIndex: 1}, + logpoller.Log{BlockNumber: 5, TxHash: common.HexToHash("0x5"), LogIndex: 1}, + ), 2) + + logs = buf.dequeueRange(1, 5, 3, 2) + require.Equal(t, 2, len(logs)) }) t.Run("dequeue doesn't return same logs again", func(t *testing.T) { @@ -327,19 +338,508 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { logpoller.Log{BlockNumber: 3, TxHash: common.HexToHash("0x3"), LogIndex: 0}, ), 3) - logs := buf.dequeueRange(3, 3, 2) + logs := buf.dequeueRange(3, 3, 2, 10) fmt.Println(logs) require.Equal(t, 1, len(logs)) - logs = buf.dequeueRange(3, 3, 2) + logs = buf.dequeueRange(3, 3, 2, 10) fmt.Println(logs) require.Equal(t, 0, len(logs)) }) } +func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { + type appendArgs struct { + fl fetchedLog + maxBlockLogs, maxUpkeepLogs int + added, dropped bool + } + + tests := []struct { + name string + blockNumber int64 + logs []fetchedLog + visited []fetchedLog + toAdd []appendArgs + expected []fetchedLog + added bool + }{ + { + name: "empty block", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "existing log", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: false, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "visited log", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: false, + }, + }, + expected: []fetchedLog{}, + }, + { + name: "upkeep log limits", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 10, + maxUpkeepLogs: 2, + added: true, + dropped: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + { + name: "block log limits", + blockNumber: 1, + logs: []fetchedLog{}, + visited: []fetchedLog{}, + toAdd: []appendArgs{ + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + }, + { + fl: fetchedLog{ + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + maxBlockLogs: 2, + maxUpkeepLogs: 4, + added: true, + dropped: true, + }, + }, + expected: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + lggr := logger.TestLogger(t) + b := fetchedBlock{ + blockNumber: tc.blockNumber, + logs: make([]fetchedLog, len(tc.logs)), + visited: make([]fetchedLog, len(tc.visited)), + } + copy(b.logs, tc.logs) + copy(b.visited, tc.visited) + + for _, args := range tc.toAdd { + dropped, added := b.Append(lggr, args.fl, args.maxBlockLogs, args.maxUpkeepLogs) + require.Equal(t, args.added, added) + if args.dropped { + require.NotNil(t, dropped.upkeepID) + } else { + require.Nil(t, dropped.upkeepID) + } + } + // clear cached logIDs + for i := range b.logs { + b.logs[i].cachedLogID = "" + } + require.Equal(t, tc.expected, b.logs) + }) + } +} +func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { + tests := []struct { + name string + blockNumber int64 + logs []fetchedLog + beforeSort []string + afterSort []string + iterations int + }{ + { + name: "no logs", + blockNumber: 10, + logs: []fetchedLog{}, + beforeSort: []string{}, + afterSort: []string{}, + }, + { + name: "single log", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockHash: common.HexToHash("0x111"), + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + }, + }, + beforeSort: []string{ + "000000000000000000000000000000000000000000000000000000000000000100000000", + }, + afterSort: []string{ + "000000000000000000000000000000000000000000000000000000000000000100000000", + }, + }, + { + name: "multiple logs with 10 iterations", + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xb711bd1103927611ee41152aa8ae27f3330"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 4, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 3, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 5, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 3, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + BlockHash: common.HexToHash("0xa25ebae1099f3fbae2525ebae279f3ae25e"), + TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), + LogIndex: 1, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + beforeSort: []string{ + "00000000000000000000000000000b711bd1103927611ee41152aa8ae27f333000000000", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000000", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000004", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000002", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000005", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000001", + }, + afterSort: []string{ + "00000000000000000000000000000b711bd1103927611ee41152aa8ae27f333000000000", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000000", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000001", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000002", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000003", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000004", + "00000000000000000000000000000a651bd1109922111ee411525ebae27f3fb600000005", + }, + iterations: 10, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + b := fetchedBlock{ + blockNumber: tc.blockNumber, + logs: make([]fetchedLog, len(tc.logs)), + } + if tc.iterations == 0 { + tc.iterations = 1 + } + // performing the same multiple times should yield the same result + // default is one iteration + for i := 0; i < tc.iterations; i++ { + copy(b.logs, tc.logs) + logIDs := getLogIds(b) + require.Equal(t, len(tc.beforeSort), len(logIDs)) + require.Equal(t, tc.beforeSort, logIDs) + b.Sort() + logIDsAfterSort := getLogIds(b) + require.Equal(t, len(tc.afterSort), len(logIDsAfterSort)) + require.Equal(t, tc.afterSort, logIDsAfterSort) + } + }) + } +} + +func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { + b1 := fetchedBlock{ + blockNumber: 1, + logs: []fetchedLog{ + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 0, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + { + log: logpoller.Log{ + BlockNumber: 1, + TxHash: common.HexToHash("0x1"), + LogIndex: 2, + }, + upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + }, + }, + } + + b2 := b1.Clone() + require.Equal(t, b1.blockNumber, b2.blockNumber) + require.Equal(t, len(b1.logs), len(b2.logs)) + require.Equal(t, b1.logs[0].log.BlockNumber, b2.logs[0].log.BlockNumber) + + b1.blockNumber = 2 + b1.logs[0].log.BlockNumber = 2 + require.NotEqual(t, b1.blockNumber, b2.blockNumber) + require.NotEqual(t, b1.logs[0].log.BlockNumber, b2.logs[0].log.BlockNumber) +} + func verifyBlockNumbers(t *testing.T, logs []fetchedLog, bns ...int64) { require.Equal(t, len(bns), len(logs), "expected length mismatch") for i, log := range logs { require.Equal(t, bns[i], log.log.BlockNumber, "wrong block number") } } + +func getLogIds(b fetchedBlock) []string { + logIDs := make([]string, len(b.logs)) + for i, l := range b.logs { + ext := ocr2keepers.LogTriggerExtension{ + TxHash: l.log.TxHash, + Index: uint32(l.log.LogIndex), + BlockHash: l.log.BlockHash, + } + logIDs[i] = hex.EncodeToString(ext.LogIdentifier()) + } + return logIDs +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go index 30994543eb6..b5f229f6015 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/integration_test.go @@ -478,10 +478,10 @@ func TestIntegration_LogRecoverer_Backfill(t *testing.T) { } lp, ethClient, utilsABI := setupDependencies(t, db, backend) filterStore := logprovider.NewUpkeepFilterStore() - origDefaultRecoveryInterval := logprovider.DefaultRecoveryInterval - logprovider.DefaultRecoveryInterval = time.Millisecond * 200 + origDefaultRecoveryInterval := logprovider.RecoveryInterval + logprovider.RecoveryInterval = time.Millisecond * 200 defer func() { - logprovider.DefaultRecoveryInterval = origDefaultRecoveryInterval + logprovider.RecoveryInterval = origDefaultRecoveryInterval }() provider, recoverer := setup(logger.TestLogger(t), lp, nil, utilsABI, &mockUpkeepStateStore{}, filterStore, opts) logProvider := provider.(logprovider.LogEventProviderTest) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go index 8fbbb1e0a9d..6b89dfd0e72 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/provider.go @@ -30,6 +30,8 @@ var ( // AllowedLogsPerUpkeep is the maximum number of logs allowed per upkeep every single call. AllowedLogsPerUpkeep = 5 + // MaxPayloads is the maximum number of payloads to return per call. + MaxPayloads = 100 readJobQueueSize = 64 readLogsTimeout = 10 * time.Second @@ -99,7 +101,7 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa return &logEventProvider{ packer: packer, lggr: lggr.Named("KeepersRegistry.LogEventProvider"), - buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), bufferMaxBlockSize, allowedLogsPerBlock), + buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), maxLogsPerBlock, maxLogsPerUpkeepInBlock), poller: poller, opts: opts, filterStore: filterStore, @@ -177,7 +179,7 @@ func (p *logEventProvider) GetLatestPayloads(ctx context.Context) ([]ocr2keepers if start <= 0 { start = 1 } - logs := p.buffer.dequeueRange(start, latest, AllowedLogsPerUpkeep) + logs := p.buffer.dequeueRange(start, latest, AllowedLogsPerUpkeep, MaxPayloads) // p.lggr.Debugw("got latest logs from buffer", "latest", latest, "diff", diff, "logs", len(logs)) @@ -318,7 +320,10 @@ func (p *logEventProvider) updateFiltersLastPoll(entries []upkeepFilter) { p.filterStore.UpdateFilters(func(orig, f upkeepFilter) upkeepFilter { if f.lastPollBlock > orig.lastPollBlock { orig.lastPollBlock = f.lastPollBlock - p.lggr.Debugw("Updated lastPollBlock", "lastPollBlock", f.lastPollBlock, "upkeepID", f.upkeepID) + if f.lastPollBlock%10 == 0 { + // print log occasionally to avoid spamming logs + p.lggr.Debugw("Updated lastPollBlock", "lastPollBlock", f.lastPollBlock, "upkeepID", f.upkeepID) + } } return orig }, entries...) diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go index 7a7dbbe46be..dbed9c591cd 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer.go @@ -13,6 +13,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/ocr2keepers/pkg/v3/random" ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg/v3/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -24,11 +25,17 @@ import ( ) var ( - DefaultRecoveryInterval = 5 * time.Second - RecoveryCacheTTL = 10*time.Minute - time.Second - GCInterval = RecoveryCacheTTL - - recoveryBatchSize = 10 + // RecoveryInterval is the interval at which the recovery scanning processing is triggered + RecoveryInterval = 5 * time.Second + // RecoveryCacheTTL is the time to live for the recovery cache + RecoveryCacheTTL = 10 * time.Minute + // GCInterval is the interval at which the recovery cache is cleaned up + GCInterval = RecoveryCacheTTL - time.Second + // MaxProposals is the maximum number of proposals that can be returned by GetRecoveryProposals + MaxProposals = 20 + // recoveryBatchSize is the number of filters to recover in a single batch + recoveryBatchSize = 10 + // recoveryLogsBuffer is the number of blocks to be used as a safety buffer when reading logs recoveryLogsBuffer = int64(200) recoveryLogsBurst = int64(500) ) @@ -244,6 +251,11 @@ func (r *logRecoverer) getLogTriggerCheckData(ctx context.Context, proposal ocr2 } func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers.UpkeepPayload, error) { + latestBlock, err := r.poller.LatestBlock(pg.WithParentCtx(ctx)) + if err != nil { + return nil, fmt.Errorf("%w: %s", ErrHeadNotAvailable, err) + } + r.lock.Lock() defer r.lock.Unlock() @@ -251,18 +263,29 @@ func (r *logRecoverer) GetRecoveryProposals(ctx context.Context) ([]ocr2keepers. return nil, nil } + allLogsCounter := 0 logsCount := map[string]int{} + r.sortPending(uint64(latestBlock)) + var results, pending []ocr2keepers.UpkeepPayload for _, payload := range r.pending { + if allLogsCounter >= MaxProposals { + // we have enough proposals, pushed the rest are pushed back to pending + pending = append(pending, payload) + continue + } uid := payload.UpkeepID.String() if logsCount[uid] >= AllowedLogsPerUpkeep { + // we have enough proposals for this upkeep, the rest are pushed back to pending pending = append(pending, payload) continue } - logsCount[uid]++ results = append(results, payload) + logsCount[uid]++ + allLogsCounter++ } + r.pending = pending r.lggr.Debugf("found %d pending payloads", len(pending)) @@ -603,3 +626,23 @@ func (r *logRecoverer) removePending(workID string) { } r.pending = updated } + +// sortPending sorts the pending list by a random order based on the normalized latest block number. +// Divided by 10 to ensure that nodes with similar block numbers won't end up with different order. +// NOTE: the lock must be held before calling this function. +func (r *logRecoverer) sortPending(latestBlock uint64) { + normalized := latestBlock / 100 + if normalized == 0 { + normalized = 1 + } + randSeed := random.GetRandomKeySource(nil, normalized) + + shuffledIDs := make(map[string]string, len(r.pending)) + for _, p := range r.pending { + shuffledIDs[p.WorkID] = random.ShuffleString(p.WorkID, randSeed) + } + + sort.SliceStable(r.pending, func(i, j int) bool { + return shuffledIDs[r.pending[i].WorkID] < shuffledIDs[r.pending[j].WorkID] + }) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go index 0a993831b7b..e7729924304 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/logprovider/recoverer_test.go @@ -31,7 +31,9 @@ import ( func TestLogRecoverer_GetRecoverables(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - r := NewLogRecoverer(logger.TestLogger(t), nil, nil, nil, nil, nil, NewOptions(200)) + lp := &lpmocks.LogPoller{} + lp.On("LatestBlock", mock.Anything).Return(int64(100), nil) + r := NewLogRecoverer(logger.TestLogger(t), lp, nil, nil, nil, nil, NewOptions(200)) tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go index 849463e53a2..1c54bf553d9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evm21/registry.go @@ -283,6 +283,7 @@ func (r *EvmRegistry) refreshActiveUpkeeps() error { switch core.GetUpkeepType(*uid) { case ocr2keepers.LogTrigger: logTriggerIDs = append(logTriggerIDs, id) + default: } }