Skip to content

Commit

Permalink
Mercury Packer (#11521)
Browse files Browse the repository at this point in the history
* Refactor encoding.Packer to have Mercury control its own interface and function implementations

* rebase and update
  • Loading branch information
shileiwill authored Dec 13, 2023
1 parent ee2996f commit 8b2c48d
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 267 deletions.
37 changes: 24 additions & 13 deletions core/scripts/chaincli/handler/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"

evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury"

"github.com/smartcontractkit/chainlink/core/scripts/chaincli/config"
"github.com/smartcontractkit/chainlink/core/scripts/common"
Expand All @@ -33,6 +32,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams"
"github.com/smartcontractkit/chainlink/v2/core/utils"
bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math"
Expand All @@ -44,6 +44,7 @@ const (
expectedTypeAndVersion = "KeeperRegistry 2.1.0"
)

var mercuryPacker = mercury.NewAbiPacker()
var packer = encoding.NewAbiPacker()

var links []string
Expand Down Expand Up @@ -258,10 +259,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) {
mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI)
lggr, _ := logger.NewLogger()
blockSub := &blockSubscriber{k.client}
streams := streams.NewStreamsLookup(packer, mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr)
streams := streams.NewStreamsLookup(mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr)

var streamsLookupErr *mercury.StreamsLookupError
streamsLookupErr, err = packer.DecodeStreamsLookupRequest(checkResult.PerformData)
streamsLookupErr, err = mercuryPacker.DecodeStreamsLookupRequest(checkResult.PerformData)
if err == nil {
message("upkeep reverted with StreamsLookup")
message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData)))
Expand All @@ -282,7 +283,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) {
message("using mercury lookup v0.2")
// check if upkeep is allowed to use mercury v0.2
var allowed bool
_, _, _, allowed, err = streams.AllowedToUseMercury(latestCallOpts, upkeepID)
_, _, _, allowed, err = streams.AllowedToUseMercury(triggerCallOpts, upkeepID)
if err != nil {
failUnknown("failed to check if upkeep is allowed to use mercury", err)
}
Expand All @@ -307,10 +308,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) {
var values [][]byte
values, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0)

if automationCheckResult.IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) {
if checkResults[0].IneligibilityReason == uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) {
resolveIneligible("upkeep used invalid revert data")
}
if automationCheckResult.PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) {
if checkResults[0].PipelineExecutionState == uint8(mercury.InvalidMercuryRequest) {
resolveIneligible("the mercury request data is invalid")
}
if err != nil {
Expand All @@ -322,10 +323,10 @@ func (k *Keeper) Debug(ctx context.Context, args []string) {
if err != nil {
failUnknown("failed to execute mercury callback ", err)
}
if automationCheckResult.IneligibilityReason != 0 {
message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", automationCheckResult.IneligibilityReason))
if checkResults[0].IneligibilityReason != 0 {
message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResults[0].IneligibilityReason))
}
upkeepNeeded, performData = automationCheckResult.Eligible, automationCheckResult.PerformData
upkeepNeeded, performData = checkResults[0].Eligible, checkResults[0].PerformData
// do tenderly simulations for checkCallback
var rawCall []byte
rawCall, err = core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData)
Expand All @@ -345,13 +346,23 @@ func (k *Keeper) Debug(ctx context.Context, args []string) {
if !upkeepNeeded {
resolveIneligible("upkeep is not needed")
}
// simulate perform ukeep
simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(latestCallOpts, upkeepID, performData)
// simulate perform upkeep
simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(triggerCallOpts, upkeepID, performData)
if err != nil {
failUnknown("failed to simulate perform upkeep: ", err)
}

// do tenderly simulation
rawCall, err := core.RegistryABI.Pack("simulatePerformUpkeep", upkeepID, performData)
if err != nil {
failUnknown("failed to pack raw simulatePerformUpkeep call", err)
}
addLink("simulatePerformUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress))

if simulateResult.Success {
resolveEligible()
} else {
resolveIneligible("simulate perform upkeep unsuccessful")
}
}

Expand Down Expand Up @@ -466,11 +477,11 @@ func warning(msg string) {
}

func resolveIneligible(msg string) {
exit(fmt.Sprintf("✅ %s: this upkeep is not currently eligible", msg), nil, 0)
exit(fmt.Sprintf("this upkeep is not eligible: %s", msg), nil, 0)
}

func resolveEligible() {
exit(" this upkeep is currently eligible", nil, 0)
exit(" this upkeep is eligible", nil, 0)
}

func rerun(msg string, err error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package encoding

import (
"math/big"

ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"

"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"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury"
)

const (
Expand Down Expand Up @@ -51,12 +48,8 @@ type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo

type Packer interface {
UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error)
UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error)
UnpackPerformResult(raw string) (uint8, bool, error)
UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error)
PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error)
UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error)
PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error)
UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error)
DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury"
)

// triggerWrapper is a wrapper for the different trigger types (log and condition triggers).
Expand Down Expand Up @@ -67,35 +66,6 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str
return result, nil
}

func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) {
return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId)
}

func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) {
out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp)
if err != nil {
return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err)
}

bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte)

return bts, nil
}

func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) {
out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp)
if err != nil {
return PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp))
}

upkeepNeeded := *abi.ConvertType(out[0], new(bool)).(*bool)
rawPerformData := *abi.ConvertType(out[1], new([]byte)).(*[]byte)
failureReason := *abi.ConvertType(out[2], new(uint8)).(*uint8)
gasUsed := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int)

return NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil
}

func (p *abiPacker) UnpackPerformResult(raw string) (uint8, bool, error) {
b, err := hexutil.Decode(raw)
if err != nil {
Expand Down Expand Up @@ -163,24 +133,6 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr
return report, nil
}

// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData)
func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) {
e := p.streamsABI.Errors["StreamsLookup"]
unpack, err := e.Unpack(data)
if err != nil {
return nil, fmt.Errorf("unpack error: %w", err)
}
errorParameters := unpack.([]interface{})

return &mercury.StreamsLookupError{
FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string),
Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string),
TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string),
Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int),
ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte),
}, nil
}

// GetIneligibleCheckResultWithoutPerformData returns an ineligible check result with ineligibility reason and pipeline execution state but without perform data
func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason uint8, state uint8, retryable bool) ocr2keepers.CheckResult {
return ocr2keepers.CheckResult{
Expand Down
Loading

0 comments on commit 8b2c48d

Please sign in to comment.