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

CCIP-4403 lbtc onchain reader #1555

Merged
merged 5 commits into from
Dec 3, 2024
Merged
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
2 changes: 1 addition & 1 deletion core/services/ocr2/plugins/ccip/ccipexec/initializers.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func NewExecServices(ctx context.Context, lggr logger.Logger, jb job.Job, srcPro

lbtcReader, err2 := srcProvider.NewTokenDataReader(ctx, ccip.EvmAddrToGeneric(pluginConfig.LBTCConfig.SourceTokenAddress))
if err2 != nil {
return nil, fmt.Errorf("new usdc reader: %w", err2)
return nil, fmt.Errorf("new lbtc reader: %w", err2)
}
tokenDataProviders[cciptypes.Address(pluginConfig.LBTCConfig.SourceTokenAddress.String())] = lbtcReader
}
Expand Down
7 changes: 3 additions & 4 deletions core/services/ocr2/plugins/ccip/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,9 @@ type USDCConfig struct {
}

type LBTCConfig struct {
SourceTokenAddress common.Address
SourceMessageTransmitterAddress common.Address
AttestationAPI string
AttestationAPITimeoutSeconds uint
SourceTokenAddress common.Address
AttestationAPI string
AttestationAPITimeoutSeconds uint
// AttestationAPIIntervalMilliseconds can be set to -1 to disable or 0 to use a default interval.
AttestationAPIIntervalMilliseconds int
}
Expand Down
9 changes: 0 additions & 9 deletions core/services/ocr2/plugins/ccip/exportinternal.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,7 @@ 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

This file was deleted.

96 changes: 78 additions & 18 deletions core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package lbtc

import (
"bytes"
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"net/url"
"sync"
Expand All @@ -15,6 +17,7 @@ import (

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/abihelpers"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/http"
)
Expand Down Expand Up @@ -72,16 +75,52 @@ type TokenDataReader struct {
type messageAttestationResponse struct {
MessageHash string `json:"message_hash"`
Status attestationStatus `json:"status"`
Attestation string `json:"attestation"`
Attestation string `json:"attestation"` // Attestation represented by abi.encode(payload, proof)
}

// TODO: Adjust after checking API docs
type attestationRequest struct {
PayloadHashes []string `json:"messageHash"`
}

type attestationResponse struct {
Attestations []messageAttestationResponse `json:"attestations"`
}

// TODO: Implement encoding/decoding

type sourceTokenData struct {
SourcePoolAddress []byte
DestTokenAddress []byte
ExtraData []byte
DestGasAmount uint32
}

func (m sourceTokenData) AbiString() string {
return `[{
"components": [
{"name": "sourcePoolAddress", "type": "bytes"},
{"name": "destTokenAddress", "type": "bytes"},
{"name": "extraData", "type": "bytes"},
{"name": "destGasAmount", "type": "uint32"}
],
"type": "tuple"
}]`
}

func (m sourceTokenData) Validate() error {
if len(m.SourcePoolAddress) == 0 {
return errors.New("sourcePoolAddress must be non-empty")
}
if len(m.DestTokenAddress) == 0 {
return errors.New("destTokenAddress must be non-empty")
}
if len(m.ExtraData) == 0 {
return errors.New("extraData must be non-empty")
}
return nil
}

var _ tokendata.Reader = &TokenDataReader{}

func NewLBTCTokenDataReader(
Expand Down Expand Up @@ -149,17 +188,16 @@ func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2E
}
}

messageBody, err := s.getLBTCMessageBody(ctx, msg, tokenIndex)
payloadHash, err := s.getLBTCPayloadHash(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)
payloadHashHex := hexutil.Encode(payloadHash[:])
s.lggr.Infow("Calling attestation API", "messageBodyHash", payloadHashHex, "messageID", msgID)

attestationResp, err := s.callAttestationApi(ctx, messageBodyHash)
attestationResp, err := s.callAttestationApi(ctx, payloadHash)
if err != nil {
return nil, err
}
Expand All @@ -171,19 +209,19 @@ func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2E
}
var attestation messageAttestationResponse
for _, attestationCandidate := range attestationResp.Attestations {
if attestationCandidate.MessageHash == messageBodyHashHex {
if attestationCandidate.MessageHash == payloadHashHex {
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)
payloadAndProof, err := hexutil.Decode(attestation.Attestation)
if err != nil {
return nil, fmt.Errorf("failed to encode messageAndAttestation : %w", err)
return nil, err
}
return messageAndAttestation, nil
return payloadAndProof, nil
case attestationStatusPending:
return nil, tokendata.ErrNotReady
case attestationStatusSubmitted:
Expand All @@ -194,24 +232,46 @@ func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2E
}
}

func (s *TokenDataReader) getLBTCMessageBody(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
return nil, nil
func (s *TokenDataReader) getLBTCPayloadHash(msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([32]byte, error) {
decodedSourceTokenData, err := abihelpers.DecodeAbiStruct[sourceTokenData](msg.SourceTokenData[tokenIndex])
if err != nil {
return [32]byte{}, err
}
destTokenData := decodedSourceTokenData.ExtraData
var payloadHash [32]byte
// We don't have better way to determine if the extraData is a payload or sha256(payload)
// Last parameter of the payload struct is 32-bytes nonce (see Lombard's Bridge._deposit(...) method),
// so we can assume that payload always exceeds 32 bytes
if len(destTokenData) != 32 {
payloadHash = sha256.Sum256(destTokenData)
s.lggr.Warnw("SourceTokenData.extraData size is not 32. Probably this is deposit payload, not sha256(payload). "+
"This message was sent when LBTC attestation was disabled onchain. Will use sha256 from this value",
"destTokenData", destTokenData, "newPayloadHash", payloadHash)
} else {
payloadHash = [32]byte(destTokenData)
}
return payloadHash, nil
}

func (s *TokenDataReader) callAttestationApi(ctx context.Context, lbtcMessageHash [32]byte) (attestationResponse, error) {
_, _, _, err := s.httpClient.Get(ctx, "", s.attestationApiTimeout)
attestationUrl := fmt.Sprintf("%s/bridge/%s/%s", s.attestationApi.String(), apiVersion, attestationPath)
request := attestationRequest{PayloadHashes: []string{hexutil.Encode(lbtcMessageHash[:])}}
encodedRequest, err := json.Marshal(request)
requestBuffer := bytes.NewBuffer(encodedRequest)
if err != nil {
return attestationResponse{}, err
}
respRaw, _, _, err := s.httpClient.Post(ctx, attestationUrl, requestBuffer, s.attestationApiTimeout)
switch {
case errors.Is(err, tokendata.ErrRateLimit):
s.setCoolDownPeriod(defaultCoolDownDuration)
return attestationResponse{}, tokendata.ErrRateLimit
case err != nil:
return attestationResponse{}, err
}
return attestationResponse{}, nil
}

func encodeMessageAndAttestation(messageBody []byte, attestation string) ([]byte, error) {
return nil, nil
var attestationResp attestationResponse
err = json.Unmarshal(respRaw, &attestationResp)
return attestationResp, err
}

func (s *TokenDataReader) setCoolDownPeriod(d time.Duration) {
Expand Down
20 changes: 20 additions & 0 deletions core/services/ocr2/plugins/ccip/tokendata/lbtc/lbtc_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package lbtc

import (
"testing"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
)

func Test_DecodeSourceTokenData(t *testing.T) {
input, err := hexutil.Decode("0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000249f00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000267d40f64ecc4d95f3e8b2237df5f37b10812c250000000000000000000000000000000000000000000000000000000000000020000000000000000000000000c47e4b3124597fdf8dd07843d4a7052f2ee80c3000000000000000000000000000000000000000000000000000000000000000e45c70a5050000000000000000000000000000000000000000000000000000000000aa36a7000000000000000000000000845f8e3c214d8d0e4d83fc094f302aa26a12a0bc0000000000000000000000000000000000000000000000000000000000014a34000000000000000000000000845f8e3c214d8d0e4d83fc094f302aa26a12a0bc00000000000000000000000062f10ce5b727edf787ea45776bd050308a61150800000000000000000000000000000000000000000000000000000000000003e6000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
decoded, err := abihelpers.DecodeAbiStruct[sourceTokenData](input)
require.NoError(t, err)
expected, err := hexutil.Decode("0x5c70a5050000000000000000000000000000000000000000000000000000000000aa36a7000000000000000000000000845f8e3c214d8d0e4d83fc094f302aa26a12a0bc0000000000000000000000000000000000000000000000000000000000014a34000000000000000000000000845f8e3c214d8d0e4d83fc094f302aa26a12a0bc00000000000000000000000062f10ce5b727edf787ea45776bd050308a61150800000000000000000000000000000000000000000000000000000000000003e60000000000000000000000000000000000000000000000000000000000000006")
require.NoError(t, err)
require.Equal(t, expected, decoded.ExtraData)
}
15 changes: 0 additions & 15 deletions core/services/relay/evm/exec_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ type SrcExecProvider struct {
maxGasPrice *big.Int
usdcReader *ccip.USDCReaderImpl
usdcConfig config.USDCConfig
lbtcReader *ccip.LBTCReaderImpl
lbtcConfig config.LBTCConfig

feeEstimatorConfig estimatorconfig.FeeEstimatorConfigProvider
Expand Down Expand Up @@ -73,13 +72,6 @@ func NewSrcExecProvider(
return nil, fmt.Errorf("new usdc reader: %w", err)
}
}
var lbtcReader *ccip.LBTCReaderImpl
if lbtcConfig.AttestationAPI != "" {
lbtcReader, err = ccip.NewLBTCReader(lggr, jobID, lbtcConfig.SourceMessageTransmitterAddress, lp, true)
if err != nil {
return nil, fmt.Errorf("new usdc reader: %w", err)
}
}

return &SrcExecProvider{
lggr: lggr,
Expand All @@ -91,7 +83,6 @@ func NewSrcExecProvider(
startBlock: startBlock,
usdcReader: usdcReader,
usdcConfig: usdcConfig,
lbtcReader: lbtcReader,
lbtcConfig: lbtcConfig,
feeEstimatorConfig: feeEstimatorConfig,
}, nil
Expand Down Expand Up @@ -127,12 +118,6 @@ func (s *SrcExecProvider) Close() error {
}
return ccip.CloseUSDCReader(s.lggr, s.lggr.Name(), s.usdcConfig.SourceMessageTransmitterAddress, s.lp)
})
unregisterFuncs = append(unregisterFuncs, func() error {
if s.lbtcConfig.AttestationAPI == "" {
return nil
}
return ccip.CloseLBTCReader(s.lggr, s.lggr.Name(), s.lbtcConfig.SourceMessageTransmitterAddress, s.lp)
})
var multiErr error
for _, fn := range unregisterFuncs {
if err := fn(); err != nil {
Expand Down
Loading