Skip to content

Commit

Permalink
Unpacking with keepers utils structs (#9754)
Browse files Browse the repository at this point in the history
* use utils abi for un/packing reports and triggers

* fixed unpacking

* lint

* mark failing tests

* comments

* comment

* Revert "mark failing tests"

This reverts commit 4a8d0f8.

* fix log provider tests

* packer tests

* encoder tests

* test all trigger cases

* add tests
  • Loading branch information
amirylm committed Jul 11, 2023
1 parent 6604c3f commit b4b6b51
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 343 deletions.
97 changes: 94 additions & 3 deletions core/services/ocr2/plugins/ocr2keeper/evm21/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1"
iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1"
)

Expand All @@ -32,12 +33,17 @@ const (

type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo

// triggerWrapper is a wrapper for the different trigger types (log and condition triggers).
// NOTE: we use log trigger because it extends condition trigger,
type triggerWrapper = automation_utils_2_1.KeeperRegistryBase21LogTrigger

type evmRegistryPackerV2_1 struct {
abi abi.ABI
abi abi.ABI
utilsAbi abi.ABI
}

func NewEvmRegistryPackerV2_1(abi abi.ABI) *evmRegistryPackerV2_1 {
return &evmRegistryPackerV2_1{abi: abi}
func NewEvmRegistryPackerV2_1(abi abi.ABI, utilsAbi abi.ABI) *evmRegistryPackerV2_1 {
return &evmRegistryPackerV2_1{abi: abi, utilsAbi: utilsAbi}
}

// TODO: remove for 2.1
Expand Down Expand Up @@ -175,3 +181,88 @@ func (rp *evmRegistryPackerV2_1) UnpackLogTriggerConfig(raw []byte) (iregistry21
}
return *converted, nil
}

// PackTrigger packs the trigger into the format expected by the contract,
// according to the upkeep type of the given id.
func (rp *evmRegistryPackerV2_1) PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) {
var trigger []byte
var err error
upkeepType := getUpkeepType(id.Bytes())
switch upkeepType {
case conditionTrigger:
trig := automation_utils_2_1.KeeperRegistryBase21ConditionalTrigger{
BlockNum: trig.BlockNum,
BlockHash: trig.BlockHash,
}
trigger, err = rp.utilsAbi.Pack("_conditionalTrigger", &trig)
case logTrigger:
logTrig := automation_utils_2_1.KeeperRegistryBase21LogTrigger{
BlockNum: trig.BlockNum,
BlockHash: trig.BlockHash,
LogIndex: trig.LogIndex,
TxHash: trig.TxHash,
}
trigger, err = rp.utilsAbi.Pack("_logTrigger", &logTrig)
default:
err = fmt.Errorf("unknown trigger type: %d", upkeepType)
}
if err != nil {
return nil, err
}
return trigger[4:], nil
}

// UnpackTrigger unpacks the trigger from the given raw data, according to the upkeep type of the given id.
func (rp *evmRegistryPackerV2_1) UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) {
upkeepType := getUpkeepType(id.Bytes())
switch upkeepType {
case conditionTrigger:
unpacked, err := rp.utilsAbi.Methods["_conditionalTrigger"].Inputs.Unpack(raw)
if err != nil {
return triggerWrapper{}, fmt.Errorf("%w: failed to unpack conditional trigger", err)
}
converted, ok := abi.ConvertType(unpacked[0], new(automation_utils_2_1.KeeperRegistryBase21ConditionalTrigger)).(*automation_utils_2_1.KeeperRegistryBase21ConditionalTrigger)
if !ok {
return automation_utils_2_1.KeeperRegistryBase21LogTrigger{}, fmt.Errorf("failed to convert type")
}
return triggerWrapper{
BlockNum: converted.BlockNum,
BlockHash: converted.BlockHash,
}, nil
case logTrigger:
unpacked, err := rp.utilsAbi.Methods["_logTrigger"].Inputs.Unpack(raw)
if err != nil {
return triggerWrapper{}, fmt.Errorf("%w: failed to unpack log trigger", err)
}
converted, ok := abi.ConvertType(unpacked[0], new(automation_utils_2_1.KeeperRegistryBase21LogTrigger)).(*automation_utils_2_1.KeeperRegistryBase21LogTrigger)
if !ok {
return automation_utils_2_1.KeeperRegistryBase21LogTrigger{}, fmt.Errorf("failed to convert type")
}
return triggerWrapper(*converted), nil
default:
return triggerWrapper{}, fmt.Errorf("unknown trigger type: %d", upkeepType)
}
}

// PackReport packs the report with abi definitions from the contract.
func (rp *evmRegistryPackerV2_1) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) {
bts, err := rp.utilsAbi.Pack("_report", &report)
if err != nil {
return nil, fmt.Errorf("%w: failed to pack report", err)
}

return bts[4:], nil
}

// UnpackReport unpacks the report from the given raw data.
func (rp *evmRegistryPackerV2_1) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) {
unpacked, err := rp.utilsAbi.Methods["_report"].Inputs.Unpack(raw)
if err != nil {
return automation_utils_2_1.KeeperRegistryBase21Report{}, fmt.Errorf("%w: failed to unpack report", err)
}
converted, ok := abi.ConvertType(unpacked[0], new(automation_utils_2_1.KeeperRegistryBase21Report)).(*automation_utils_2_1.KeeperRegistryBase21Report)
if !ok {
return automation_utils_2_1.KeeperRegistryBase21Report{}, fmt.Errorf("failed to convert type")
}
return *converted, nil
}
141 changes: 116 additions & 25 deletions core/services/ocr2/plugins/ocr2keeper/evm21/abi_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evm

import (
"fmt"
"math/big"
"strings"
"testing"
Expand All @@ -10,10 +11,13 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/assert"

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1"
iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1"

ocr2keepers "github.com/smartcontractkit/ocr2keepers/pkg"
)

func TestUnpackTransmitTxInputErrors(t *testing.T) {
func TestPacker_UnpackTransmitTxInputErrors(t *testing.T) {

tests := []struct {
Name string
Expand All @@ -30,22 +34,15 @@ func TestUnpackTransmitTxInputErrors(t *testing.T) {
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
abi, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI))
assert.Nil(t, err)

packer := NewEvmRegistryPackerV2_1(abi)
packer, err := newPacker()
assert.NoError(t, err)
_, err = packer.UnpackTransmitTxInput(hexutil.MustDecode(test.RawData))
assert.NotNil(t, err)
})
}
}

func TestUnpackPerformResult(t *testing.T) {
registryABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI))
if err != nil {
assert.Nil(t, err)
}

func TestPacker_UnpackPerformResult(t *testing.T) {
tests := []struct {
Name string
RawData string
Expand All @@ -57,20 +54,16 @@ func TestUnpackPerformResult(t *testing.T) {
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
packer := NewEvmRegistryPackerV2_1(registryABI)
packer, err := newPacker()
assert.NoError(t, err)
rs, err := packer.UnpackPerformResult(test.RawData)
assert.Nil(t, err)
assert.True(t, rs)
})
}
}

func TestUnpackCheckCallbackResult(t *testing.T) {
registryABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI))
if err != nil {
assert.Nil(t, err)
}

func TestPacker_UnpackCheckCallbackResult(t *testing.T) {
tests := []struct {
Name string
CallbackResp []byte
Expand Down Expand Up @@ -106,7 +99,9 @@ func TestUnpackCheckCallbackResult(t *testing.T) {
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
packer := NewEvmRegistryPackerV2_1(registryABI)
packer, err := newPacker()
assert.NoError(t, err)

needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp)

if test.ErrorString != "" {
Expand All @@ -122,9 +117,7 @@ func TestUnpackCheckCallbackResult(t *testing.T) {
}
}

func TestUnpackLogTriggerConfig(t *testing.T) {
keeperRegistryABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI))
assert.NoError(t, err)
func TestPacker_UnpackLogTriggerConfig(t *testing.T) {
tests := []struct {
name string
raw []byte
Expand Down Expand Up @@ -154,11 +147,10 @@ func TestUnpackLogTriggerConfig(t *testing.T) {
},
}

packer := NewEvmRegistryPackerV2_1(keeperRegistryABI)

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {

packer, err := newPacker()
assert.NoError(t, err)
res, err := packer.UnpackLogTriggerConfig(tc.raw)
if tc.errored {
assert.Error(t, err)
Expand All @@ -169,3 +161,102 @@ func TestUnpackLogTriggerConfig(t *testing.T) {
})
}
}

func TestPacker_PackingTrigger(t *testing.T) {
tests := []struct {
name string
id ocr2keepers.UpkeepIdentifier
trigger triggerWrapper
encoded []byte
err error
}{
{
"happy flow log trigger",
append([]byte{1}, common.LeftPadBytes([]byte{1}, 15)...),
triggerWrapper{
BlockNum: 1,
BlockHash: common.HexToHash("0x01111111"),
LogIndex: 1,
TxHash: common.HexToHash("0x01111111"),
},
func() []byte {
b, _ := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000001111111000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111")
return b
}(),
nil,
},
{
"happy flow conditional trigger",
append([]byte{1}, common.LeftPadBytes([]byte{0}, 15)...),
triggerWrapper{
BlockNum: 1,
BlockHash: common.HexToHash("0x01111111"),
},
func() []byte {
b, _ := hexutil.Decode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111")
return b
}(),
nil,
},
{
"invalid type",
append([]byte{1}, common.LeftPadBytes([]byte{8}, 15)...),
triggerWrapper{
BlockNum: 1,
BlockHash: common.HexToHash("0x01111111"),
},
[]byte{},
fmt.Errorf("unknown trigger type: %d", 8),
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
packer, err := newPacker()
assert.NoError(t, err)
id, ok := big.NewInt(0).SetString(hexutil.Encode(tc.id)[2:], 16)
assert.True(t, ok)

encoded, err := packer.PackTrigger(id, tc.trigger)
if tc.err != nil {
assert.EqualError(t, err, tc.err.Error())
} else {
assert.NoError(t, err)
assert.Equal(t, tc.encoded, encoded)
decoded, err := packer.UnpackTrigger(id, encoded)
assert.NoError(t, err)
assert.Equal(t, tc.trigger.BlockNum, decoded.BlockNum)
}
})
}

t.Run("unpacking invalid trigger", func(t *testing.T) {
packer, err := newPacker()
assert.NoError(t, err)
_, err = packer.UnpackTrigger(big.NewInt(0), []byte{1, 2, 3})
assert.Error(t, err)
})

t.Run("unpacking unknown type", func(t *testing.T) {
packer, err := newPacker()
assert.NoError(t, err)
uid := append([]byte{1}, common.LeftPadBytes([]byte{8}, 15)...)
id, ok := big.NewInt(0).SetString(hexutil.Encode(uid)[2:], 16)
assert.True(t, ok)
decoded, _ := hexutil.Decode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000001111111")
_, err = packer.UnpackTrigger(id, decoded)
assert.EqualError(t, err, "unknown trigger type: 8")
})
}

func newPacker() (*evmRegistryPackerV2_1, error) {
keepersABI, err := abi.JSON(strings.NewReader(iregistry21.IKeeperRegistryMasterABI))
if err != nil {
return nil, err
}
utilsABI, err := abi.JSON(strings.NewReader(automation_utils_2_1.AutomationUtilsABI))
if err != nil {
return nil, err
}
return NewEvmRegistryPackerV2_1(keepersABI, utilsABI), nil
}
Loading

0 comments on commit b4b6b51

Please sign in to comment.