Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load tests/2.11.0 ccip1.4 #1023

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/big-bats-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

Reducing the scope of 0233 migration to include only 5th word index which is required for CCIP #db_update
5 changes: 5 additions & 0 deletions .changeset/nice-falcons-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

Fix reports count calculation method
5 changes: 5 additions & 0 deletions .changeset/seven-hats-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

#internal Remove unnecessary marshall/unmarshall of CommitObservation
5 changes: 5 additions & 0 deletions .changeset/six-berries-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

#bugfix #updated Optimize OnRamp.IsSourceCursed by caching RMN contract and StaticConfig - 30x faster
5 changes: 5 additions & 0 deletions .changeset/sixty-spiders-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

#updated Optimizing ABIEncode and ABIDecode by caching abiStr
5 changes: 5 additions & 0 deletions .changeset/twelve-kings-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

#internal Improve performance
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.17.0
github.com/shopspring/decimal v1.3.1
github.com/smartcontractkit/chain-selectors v1.0.16
github.com/smartcontractkit/chain-selectors v1.0.17
github.com/smartcontractkit/chainlink-automation v1.0.2
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240410191726-b8a7349cd5d3
github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1178,8 +1178,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartcontractkit/chain-selectors v1.0.16 h1:uVoitoL5KVqGbU89b6W9gECwIvcdZh/w8MI/9JfEoy8=
github.com/smartcontractkit/chain-selectors v1.0.16/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chain-selectors v1.0.17 h1:otOlYUnutS8oQBEAi9RLQICqZP0Nxy0k8vOZuSMJa4w=
github.com/smartcontractkit/chain-selectors v1.0.17/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.2 h1:xsfyuswL15q2YBGQT3qn2SBz6fnSKiSW7XZ8IZQLpnI=
github.com/smartcontractkit/chainlink-automation v1.0.2/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240410191726-b8a7349cd5d3 h1:W8XC1b0GDM0OSzvHvUEFTaZUtognWVkEjCSW2nKQ1mc=
Expand Down
87 changes: 82 additions & 5 deletions core/services/ocr2/plugins/ccip/abihelpers/abi_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import (
"fmt"
"math/big"
"strings"
"sync"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
)

func MustGetEventID(name string, abi2 abi.ABI) common.Hash {
Expand Down Expand Up @@ -67,18 +66,38 @@ type AbiDefinedValid interface {
Validate() error
}

func ABIEncode(abiStr string, values ...interface{}) ([]byte, error) {
inAbi, err := getABI(abiStr, ENCODE)
if err != nil {
return nil, err
}
res, err := inAbi.Pack("method", values...)
if err != nil {
return nil, err
}
return res[4:], nil
}

func ABIDecode(abiStr string, data []byte) ([]interface{}, error) {
inAbi, err := getABI(abiStr, DECODE)
if err != nil {
return nil, err
}
return inAbi.Unpack("method", data)
}

func EncodeAbiStruct[T AbiDefined](decoded T) ([]byte, error) {
return utils.ABIEncode(decoded.AbiString(), decoded)
return ABIEncode(decoded.AbiString(), decoded)
}

func EncodeAddress(address common.Address) ([]byte, error) {
return utils.ABIEncode(`[{"type":"address"}]`, address)
return ABIEncode(`[{"type":"address"}]`, address)
}

func DecodeAbiStruct[T AbiDefinedValid](encoded []byte) (T, error) {
var empty T

decoded, err := utils.ABIDecode(empty.AbiString(), encoded)
decoded, err := ABIDecode(empty.AbiString(), encoded)
if err != nil {
return empty, err
}
Expand Down Expand Up @@ -109,3 +128,61 @@ func DecodeOCR2Config(encoded []byte) (*ocr2aggregator.OCR2AggregatorConfigSet,
}
return unpacked, nil
}

// create const encode and decode
const (
ENCODE = iota
DECODE
)

type abiCache struct {
cache map[string]*abi.ABI
mu *sync.RWMutex
}

func newAbiCache() *abiCache {
return &abiCache{
cache: make(map[string]*abi.ABI),
mu: &sync.RWMutex{},
}
}

// Global cache for ABIs to avoid parsing the same ABI multiple times
// As the module is already a helper module and not a service, we can keep the cache global
// It's private to the package and can't be accessed from outside
var myAbiCache = newAbiCache()

// This Function is used to get the ABI from the cache or create a new one and cache it for later use
// operationType is used to differentiate between encoding and decoding
// encoding uses a definition with `inputs` and decoding uses a definition with `outputs` (check inDef)
func getABI(abiStr string, operationType uint8) (*abi.ABI, error) {

var operationStr string
switch operationType {
case ENCODE:
operationStr = "inputs"
case DECODE:
operationStr = "outputs"
default:
return nil, fmt.Errorf("invalid operation type")
}

inDef := fmt.Sprintf(`[{ "name" : "method", "type": "function", "%s": %s}]`, operationStr, abiStr)

myAbiCache.mu.RLock()
if cachedAbi, found := myAbiCache.cache[inDef]; found {
myAbiCache.mu.RUnlock() // unlocking before returning
return cachedAbi, nil
}
myAbiCache.mu.RUnlock()

res, err := abi.JSON(strings.NewReader(inDef))
if err != nil {
return nil, err
}

myAbiCache.mu.Lock()
defer myAbiCache.mu.Unlock()
myAbiCache.cache[inDef] = &res
return &res, nil
}
75 changes: 75 additions & 0 deletions core/services/ocr2/plugins/ccip/abihelpers/abi_helpers_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package abihelpers

import (
"bytes"
"fmt"
"math"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
)

func TestProofFlagToBits(t *testing.T) {
Expand Down Expand Up @@ -70,3 +73,75 @@ func TestEvmWord(t *testing.T) {
})
}
}

func TestABIEncodeDecode(t *testing.T) {
abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
values := []interface{}{struct {
Int1 *big.Int `json:"int1"`
Int2 *big.Int `json:"int2"`
}{big.NewInt(10), big.NewInt(12)}}

// First encoding, should call the underlying utils.ABIEncode
encoded, err := ABIEncode(abiStr, values...)
assert.NoError(t, err)
assert.NotNil(t, encoded)

// Second encoding, should retrieve from cache
// we're just testing here that it returns same result
encodedAgain, err := ABIEncode(abiStr, values...)

assert.NoError(t, err)
assert.True(t, bytes.Equal(encoded, encodedAgain))

// Should be able to decode it back to the original values
decoded, err := ABIDecode(abiStr, encoded)
assert.NoError(t, err)
assert.Equal(t, decoded, values)
}

func BenchmarkComparisonEncode(b *testing.B) {
abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
values := []interface{}{struct {
Int1 *big.Int `json:"int1"`
Int2 *big.Int `json:"int2"`
}{big.NewInt(10), big.NewInt(12)}}

b.Run("WithoutCache", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = utils.ABIEncode(abiStr, values...)
}
})

// Warm up the cache
_, _ = ABIEncode(abiStr, values...)

b.Run("WithCache", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = ABIEncode(abiStr, values...)
}
})
}

func BenchmarkComparisonDecode(b *testing.B) {
abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
values := []interface{}{struct {
Int1 *big.Int `json:"int1"`
Int2 *big.Int `json:"int2"`
}{big.NewInt(10), big.NewInt(12)}}
data, _ := utils.ABIEncode(abiStr, values...)

b.Run("WithoutCache", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = utils.ABIDecode(abiStr, data)
}
})

// Warm up the cache
_, _ = ABIDecode(abiStr, data)

b.Run("WithCache", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, _ = ABIDecode(abiStr, data)
}
})
}
18 changes: 9 additions & 9 deletions core/services/ocr2/plugins/ccip/ccipexec/ocr2.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const (
MaximumAllowedTokenDataWaitTimePerBatch = 2 * time.Second

// MessagesIterationStep limits number of messages fetched to memory at once when iterating through unexpired CommitRoots
MessagesIterationStep = 800
MessagesIterationStep = 1024
)

var (
Expand Down Expand Up @@ -1024,17 +1024,17 @@ func (r *ExecutionReportingPlugin) ensurePriceRegistrySynchronization(ctx contex
// because it picks messages and execution states based on the report[0].Interval.Min - report[len-1].Interval.Max range.
// Having unexpiredReports not sorted properly will lead to fetching more messages and execution states to the memory than the messagesLimit provided.
// However, logs from LogPoller are returned ordered by (block_number, log_index), so it should preserve the order of Interval.Min.
// Single CommitRoot can have up to 256 messages, with current MessagesIterationStep of 800, it means processing 4 CommitRoots at once.
// Single CommitRoot can have up to 256 messages, with current MessagesIterationStep of 1024, it means processing 4 CommitRoots at once.
func selectReportsToFillBatch(unexpiredReports []cciptypes.CommitStoreReport, messagesLimit uint64) ([]cciptypes.CommitStoreReport, int) {
currentNumberOfMessages := uint64(0)
var index int

for index = range unexpiredReports {
currentNumberOfMessages += unexpiredReports[index].Interval.Max - unexpiredReports[index].Interval.Min + 1
if currentNumberOfMessages >= messagesLimit {
nbReports := 0
for _, report := range unexpiredReports {
reportMsgCount := report.Interval.Max - report.Interval.Min + 1
if currentNumberOfMessages+reportMsgCount > messagesLimit {
break
}
currentNumberOfMessages += reportMsgCount
nbReports++
}
index = min(index+1, len(unexpiredReports))
return unexpiredReports[:index], index
return unexpiredReports[:nbReports], nbReports
}
Loading
Loading