Skip to content

Commit

Permalink
mimicing LP
Browse files Browse the repository at this point in the history
  • Loading branch information
dhaidashenko committed Feb 6, 2025
1 parent ff42fa4 commit 7bc5663
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pkg/solana/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ func (c *chain) Start(ctx context.Context) error {
startAll := []services.StartClose{c.txm, c.balanceMonitor}
if c.cfg.MultiNode.Enabled() {
c.lggr.Debug("Starting multinode")
startAll = append(startAll, c.multiNode, c.txSender)
startAll = append(startAll, c.multiNode, c.txSender, c.lp)
}
return ms.Start(ctx, startAll...)
})
Expand Down
13 changes: 12 additions & 1 deletion pkg/solana/logpoller/log_poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"fmt"
"iter"
"math"
"slices"
"os"
"time"

"github.com/gagliardetto/solana-go/rpc"
Expand Down Expand Up @@ -68,6 +68,17 @@ type Service struct {
}

func New(lggr logger.SugaredLogger, orm ORM, cl RPCClient) *Service {
logPollerTest := os.Getenv("LOG_POLLER_TEST")
switch logPollerTest {
case "MIMIC":
lggr.Criticalw("Starting in testing mode", "test", logPollerTest)
return newMimicingLogPoller(lggr, orm, cl)
default:
return newService(lggr, orm, cl)
}
}

func newService(lggr logger.SugaredLogger, orm ORM, cl RPCClient) *Service {
lggr = logger.Sugared(logger.Named(lggr, "LogPoller"))
lp := &Service{
orm: orm,
Expand Down
155 changes: 155 additions & 0 deletions pkg/solana/logpoller/mimicing_log_poller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package logpoller

import (
"context"
"encoding/json"
"fmt"
"os"
"slices"
"strings"
"time"

"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"

"github.com/smartcontractkit/chainlink-common/pkg/logger"

solanaIDL "github.com/smartcontractkit/chainlink-ccip/chains/solana"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/client"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"
)

func newMimicingLogPoller(lggr logger.SugaredLogger, orm ORM, cl RPCClient) *Service {
sourceContractStr := os.Getenv("SOURCE_CONTRACT_ADDRESS")
if sourceContractStr == "" {
panic(fmt.Errorf("env variable SOURCE_CONTRACT_ADDRESS not set"))
}

sourceContract, err := solana.PublicKeyFromBase58(sourceContractStr)
if err != nil {
panic(fmt.Errorf("invalid address %s: %w", sourceContractStr, err))
}

wrappedCl := newWrappedClient(cl, sourceContract)
service := newService(lggr, orm, wrappedCl)
go func(lp *Service) {
for {
err := tryRegisterCCIPMessageSentFilter(context.Background(), lp)
if err == nil {
lp.lggr.Infow("hardcoded filter registered successfully")
return
}

lp.lggr.Errorw("failed to register hardcoded filter", "err", err)
time.Sleep(1 * time.Second)
}
}(service)
return service
}

func tryRegisterCCIPMessageSentFilter(ctx context.Context, lp *Service) error {
ctx, cancel := lp.eng.Ctx(ctx)
defer cancel()
addr, err := solana.PublicKeyFromBase58(targetContract)
if err != nil {
return fmt.Errorf("invalid address %s: %w", targetContract, err)
}
var idl codec.IDL
err = json.Unmarshal([]byte(solanaIDL.FetchCCIPRouterIDL()), &idl)
if err != nil {
return fmt.Errorf("invalid idl: %w", err)
}

ccipMsgSentIndex := -1
for i, event := range idl.Events {
if event.Name == "CCIPMessageSent" {
ccipMsgSentIndex = i
break
}
}

slot, err := lp.client.SlotHeightWithCommitment(ctx, rpc.CommitmentFinalized)
if err != nil {
return fmt.Errorf("failed to get latest slot: %w", err)
}

startingBlock := slot - 72000 // 8 hours delay
version := client.MaxSupportTransactionVersion
block, err := lp.client.GetBlockWithOpts(ctx, startingBlock, &rpc.GetBlockOpts{MaxSupportedTransactionVersion: &version})
if err != nil {
return fmt.Errorf("failed to get starting block %d: %w", startingBlock, err)
}

lp.lggr.Infow("registering CCIPMessageSentFilter", "startingBlock", startingBlock, "blockTime", block.BlockTime.Time())

if ccipMsgSentIndex == -1 {
return fmt.Errorf("failed to find CCIPMessageSent event")
}
err = lp.RegisterFilter(ctx, Filter{
Name: "hardcoded-filter",
Address: PublicKey(addr),
EventName: "CCIPMessageSent",
EventSig: NewEventSignatureFromName("CCIPMessageSent"),
StartingBlock: int64(startingBlock), //nolint:gosec
EventIdl: EventIdl{
Event: idl.Events[ccipMsgSentIndex],
Types: idl.Types,
},
SubkeyPaths: SubKeyPaths{[]string{"SequenceNumber"}, []string{"Message", "Sender"}, []string{"Message", "Receiver"}},
Retention: time.Hour * 24 * 8,
})
if err != nil {
return fmt.Errorf("could not register filter: %w", err)
}

return nil
}

// mimicContractClient - acts as if targetContract was actually deployed on chain and was producing transactions
// that were produced by sourceContract.
type mimicContractClient struct {
RPCClient
sourceContract string
sourceContractPub solana.PublicKey
}

func newWrappedClient(rpc RPCClient, sourceContract solana.PublicKey) *mimicContractClient {
return &mimicContractClient{
RPCClient: rpc,
sourceContract: sourceContract.String(),
sourceContractPub: sourceContract,
}
}

const targetContract = "C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8"

var logs = []string{"Program C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8 invoke [1]", "Program log: Instruction: CcipSend", "Program 11111111111111111111111111111111 invoke [2]", "Program 11111111111111111111111111111111 success", "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", "Program log: Instruction: TransferChecked", "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6346 of 144955 compute units", "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", "Program data: F01Jt3u5czkVAAAAAAAAAAEAAAAAAAAAWh4VLLFCqAPcGVT5wq/rwLyiQ9AKf3hfvVmMsnhXVq8PAAAAAAAAABUAAAAAAAAAAQAAAAAAAAABAAAAAAAAANZgmT5JsvDT9xpUL9LlwegHX/nAyE84tlwHTogTVc59RwAAAENDSVAgb24gU29sYW5hIGlzIGF3ZXNvbWUhISBUb2tlbmtlZ1FmZVp5aU53QUpiTmJHS1BGWENXdUJ2ZjlTczYyM1ZRNURBIAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAiBMAAAAAAAAAAAAAAAAAAAAGm4hX/quBhPtof2NGGMA12sQ53BrrO1WYoPAAAAAAAQAAAABepiIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl3AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "Program C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8 consumed 65756 of 200000 compute units", "Program C8WSPj3yyus1YN3yNB6YA5zStYtbjQWtpmKadmvyUXq8 success"}

func (c *mimicContractClient) GetBlockWithOpts(ctx context.Context, slot uint64, opts *rpc.GetBlockOpts) (*rpc.GetBlockResult, error) {
blockResult, err := c.RPCClient.GetBlockWithOpts(ctx, slot, opts)
if err != nil {
return nil, err
}

// replace logs
start := -1
for i, tx := range blockResult.Transactions {
idx := slices.IndexFunc(tx.Meta.LogMessages, func(s string) bool {
return strings.Contains(s, c.sourceContract)
})
if idx != -1 {
start++
tx.Meta.LogMessages = logs
blockResult.Transactions[start] = blockResult.Transactions[i]
}
}

blockResult.Transactions = blockResult.Transactions[:start+1]

return blockResult, nil
}

func (c *mimicContractClient) GetSignaturesForAddressWithOpts(ctx context.Context, pubKey solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) {
return c.RPCClient.GetSignaturesForAddressWithOpts(ctx, c.sourceContractPub, opts)
}

0 comments on commit 7bc5663

Please sign in to comment.