Skip to content

Commit

Permalink
CCIP-4403 skeleton: lbtc offchain attestation
Browse files Browse the repository at this point in the history
  • Loading branch information
bukata-sa committed Nov 29, 2024
1 parent 0be81b0 commit 79b9108
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 73 deletions.
14 changes: 14 additions & 0 deletions core/services/ocr2/plugins/ccip/ccipexec/initializers.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ func NewExecServices(ctx context.Context, lggr logger.Logger, jb job.Job, srcPro
}
tokenDataProviders[cciptypes.Address(pluginConfig.USDCConfig.SourceTokenAddress.String())] = usdcReader
}
// init lbtc token data provider
if pluginConfig.LBTCConfig.AttestationAPI != "" {
lggr.Infof("LBTC token data provider enabled")
err2 := pluginConfig.LBTCConfig.ValidateLBTCConfig()
if err2 != nil {
return nil, err2
}

lbtcReader, err2 := srcProvider.NewTokenDataReader(ctx, ccip.EvmAddrToGeneric(pluginConfig.LBTCConfig.SourceTokenAddress))
if err2 != nil {
return nil, fmt.Errorf("new usdc reader: %w", err2)
}
tokenDataProviders[cciptypes.Address(pluginConfig.LBTCConfig.SourceTokenAddress.String())] = lbtcReader
}

// Prom wrappers
onRampReader = observability.NewObservedOnRampReader(onRampReader, srcChainID, ccip.ExecPluginLabel)
Expand Down
4 changes: 0 additions & 4 deletions core/services/ocr2/plugins/ccip/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,5 @@ func (lc *LBTCConfig) ValidateLBTCConfig() error {
if lc.SourceTokenAddress == utils.ZeroAddress {
return errors.New("LBTCConfig: SourceTokenAddress is required")
}
if lc.SourceMessageTransmitterAddress == utils.ZeroAddress {
return errors.New("LBTCConfig: SourceMessageTransmitterAddress is required")
}

return nil
}
9 changes: 9 additions & 0 deletions core/services/ocr2/plugins/ccip/exportinternal.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,16 @@ func CloseUSDCReader(lggr logger.Logger, jobID string, transmitter common.Addres
return ccipdata.CloseUSDCReader(lggr, jobID, transmitter, lp)
}

func NewLBTCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller, registerFilters bool) (*ccipdata.LBTCReaderImpl, error) {
return ccipdata.NewLBTCReader(lggr, jobID, transmitter, lp, registerFilters)
}

func CloseLBTCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller) error {
return ccipdata.CloseLBTCReader(lggr, jobID, transmitter, lp)
}

type USDCReaderImpl = ccipdata.USDCReaderImpl
type LBTCReaderImpl = ccipdata.LBTCReaderImpl

var DefaultRpcBatchSizeLimit = rpclib.DefaultRpcBatchSizeLimit
var DefaultRpcBatchBackOffMultiplier = rpclib.DefaultRpcBatchBackOffMultiplier
Expand Down
18 changes: 18 additions & 0 deletions core/services/ocr2/plugins/ccip/internal/ccipdata/lbtc_reader.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
package ccipdata

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

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

// TODO: Implement lbtc token reader
type LBTCReader interface {
}

type LBTCReaderImpl struct {
}

func NewLBTCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller, registerFilters bool) (*LBTCReaderImpl, error) {
return &LBTCReaderImpl{}, nil
}

func CloseLBTCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller) error {
return nil
}
91 changes: 81 additions & 10 deletions core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package lbtc

import (
"context"
"errors"
"crypto/sha256"
"fmt"
"net/url"
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"golang.org/x/time/rate"

cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/http"
"golang.org/x/time/rate"
)

// TODO: double check the validty of default values for lombard's API after checking docs
Expand Down Expand Up @@ -55,7 +58,6 @@ var (

type TokenDataReader struct {
lggr logger.Logger
lbtcReader ccipdata.LBTCReader
httpClient http.IHttpClient
attestationApi *url.URL
attestationApiTimeout time.Duration
Expand All @@ -78,13 +80,19 @@ type attestationResponse struct {
Attestations []messageAttestationResponse `json:"attestations"`
}

type SourceTokenData struct {
sourcePoolAddress []byte
destTokenAddress []byte
extraData []byte
destGasAmount uint32
}

// TODO: Implement encoding/decoding

var _ tokendata.Reader = &TokenDataReader{}

func NewLBTCTokenDataReader(
lggr logger.Logger,
lbtcReader ccipdata.LBTCReader,
lbtcAttestationApi *url.URL,
lbtcAttestationApiTimeoutSeconds int,
lbtcTokenAddress common.Address,
Expand All @@ -103,7 +111,6 @@ func NewLBTCTokenDataReader(

return &TokenDataReader{
lggr: lggr,
lbtcReader: lbtcReader,
httpClient: http.NewObservedIHttpClient(&http.HttpClient{}),
attestationApi: lbtcAttestationApi,
attestationApiTimeout: timeout,
Expand All @@ -121,7 +128,6 @@ func NewLBTCTokenDataReaderWithHttpClient(
) *TokenDataReader {
return &TokenDataReader{
lggr: origin.lggr,
lbtcReader: origin.lbtcReader,
httpClient: httpClient,
attestationApi: origin.attestationApi,
attestationApiTimeout: origin.attestationApiTimeout,
Expand All @@ -133,15 +139,80 @@ func NewLBTCTokenDataReaderWithHttpClient(

// ReadTokenData queries the LBTC attestation API.
func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
// TODO: Implement
if tokenIndex < 0 || tokenIndex >= len(msg.TokenAmounts) {
return nil, fmt.Errorf("token index out of bounds")
}

if s.inCoolDownPeriod() {
// rate limiting cool-down period, we prevent new requests from being sent
return nil, tokendata.ErrRequestsBlocked
}

if s.rate != nil {
// Wait blocks until it the attestation API can be called or the
// context is Done.
if waitErr := s.rate.Wait(ctx); waitErr != nil {
return nil, fmt.Errorf("lbtc rate limiting error: %w", waitErr)
}
}

messageBody, err := s.getLBTCMessageBody(ctx, msg, tokenIndex)
if err != nil {
return []byte{}, errors.Wrap(err, "failed getting the LBTC message body")
}

msgID := hexutil.Encode(msg.MessageID[:])
messageBodyHash := sha256.Sum256(messageBody)
messageBodyHashHex := hexutil.Encode(messageBodyHash[:])
s.lggr.Infow("Calling attestation API", "messageBodyHash", messageBodyHashHex, "messageID", msgID)

attestationResp, err := s.callAttestationApi(ctx, messageBodyHash)
if err != nil {
return nil, err
}
if attestationResp.Attestations == nil || len(attestationResp.Attestations) == 0 {
return nil, errors.New("attestation response is empty")
}
if len(attestationResp.Attestations) > 1 {
s.lggr.Warnw("Multiple attestations received, expected one", "attestations", attestationResp.Attestations)
}
var attestation messageAttestationResponse
for _, attestationCandidate := range attestationResp.Attestations {
if attestationCandidate.MessageHash == messageBodyHashHex {
attestation = attestationCandidate
}
}
s.lggr.Infow("Got response from attestation API", "messageID", msgID,
"attestationStatus", attestation.Status, "attestation", attestation)
switch attestation.Status {
case attestationStatusSessionApproved:
messageAndAttestation, err := encodeMessageAndAttestation(messageBody, attestation.Attestation)
if err != nil {
return nil, fmt.Errorf("failed to encode messageAndAttestation : %w", err)
}
return messageAndAttestation, nil
case attestationStatusPending:
return nil, tokendata.ErrNotReady
case attestationStatusSubmitted:
return nil, tokendata.ErrNotReady
default:
s.lggr.Errorw("Unexpected response from attestation API", "attestation", attestation)
return nil, ErrUnknownResponse
}
}

func (s *TokenDataReader) getLBTCMessageBody(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
return nil, nil
}

func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHash [32]byte) (attestationResponse, error) {
// TODO: Implement after checking API docs
func (s *TokenDataReader) callAttestationApi(ctx context.Context, lbtcMessageHash [32]byte) (attestationResponse, error) {
return attestationResponse{}, nil
}

func encodeMessageAndAttestation(messageBody []byte, attestation string) ([]byte, error) {
return nil, nil
}

func (s *TokenDataReader) setCoolDownPeriod(d time.Duration) {
s.coolDownMu.Lock()
if d > maxCoolDownDuration {
Expand Down
8 changes: 2 additions & 6 deletions core/services/relay/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,6 @@ func (r *Relayer) NewCCIPExecProvider(rargs commontypes.RelayArgs, pargs commont
return nil, err
}

usdcConfig := execPluginConfig.USDCConfig

feeEstimatorConfig := estimatorconfig.NewFeeEstimatorConfigService()

// CCIPExec reads when dest chain is mantle, and uses it to calc boosting in batching
Expand All @@ -591,10 +589,8 @@ func (r *Relayer) NewCCIPExecProvider(rargs commontypes.RelayArgs, pargs commont
r.chain.LogPoller(),
execPluginConfig.SourceStartBlock,
execPluginConfig.JobID,
usdcConfig.AttestationAPI,
int(usdcConfig.AttestationAPITimeoutSeconds),
usdcConfig.AttestationAPIIntervalMilliseconds,
usdcConfig.SourceMessageTransmitterAddress,
execPluginConfig.USDCConfig,
execPluginConfig.LBTCConfig,
feeEstimatorConfig,
)
}
Expand Down
Loading

0 comments on commit 79b9108

Please sign in to comment.