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

feat(rfq-guard): v2 guard logic [SLT-387] #3324

Merged
merged 18 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
37 changes: 28 additions & 9 deletions services/rfq/guard/guardconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ type Config struct {

// ChainConfig represents the configuration for a chain.
type ChainConfig struct {
// Bridge is the rfq bridge contract address.
RFQAddress string `yaml:"rfq_address"`
// RFQAddressV1 is the rfq bridge contract address.
RFQAddressV1 *string `yaml:"rfq_address_v1"`
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
// RFQAddressV2 is the rfq bridge contract address.
RFQAddressV2 string `yaml:"rfq_address_v2"`
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure Consistent Types for RFQAddressV1 and RFQAddressV2

RFQAddressV1 is declared as a pointer to string (*string), whereas RFQAddressV2 is declared as a string (string). This inconsistency may lead to confusion and potential errors in handling these fields. If both addresses are required configurations, consider using string for both. If RFQAddressV1 is optional and may be nil, ensure this distinction is clearly documented and consistently handled throughout the codebase.

Suggested Change:

Option 1: If both addresses are required:

-	RFQAddressV1 *string `yaml:"rfq_address_v1"`
+	RFQAddressV1 string  `yaml:"rfq_address_v1"`

Option 2: If both addresses can be optional:

-	RFQAddressV2 string  `yaml:"rfq_address_v2"`
+	RFQAddressV2 *string `yaml:"rfq_address_v2"`

Committable suggestion was skipped due to low confidence.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dwasse I agree with the Rabbit that highlighting the fields as optional/required would be helpful here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

// Confirmations is the number of required confirmations.
Confirmations uint64 `yaml:"confirmations"`
}
Expand Down Expand Up @@ -66,12 +68,19 @@ func LoadConfig(path string) (config Config, err error) {
// Validate validates the config.
func (c Config) Validate() (err error) {
for chainID := range c.Chains {
addr, err := c.GetRFQAddress(chainID)
addrV1, err := c.GetRFQAddressV1(chainID)
if err != nil {
return fmt.Errorf("could not get rfq address: %w", err)
}
if !common.IsHexAddress(addr) {
return fmt.Errorf("invalid rfq address: %s", addr)
if addrV1 != nil && !common.IsHexAddress(*addrV1) {
return fmt.Errorf("invalid rfq address: %s", *addrV1)
}
addrV2, err := c.GetRFQAddressV2(chainID)
if err != nil {
return fmt.Errorf("could not get rfq address: %w", err)
}
if !common.IsHexAddress(addrV2) {
return fmt.Errorf("invalid rfq address: %s", addrV2)
}
}

Expand All @@ -83,13 +92,22 @@ func (c Config) GetChains() map[int]ChainConfig {
return c.Chains
}

// GetRFQAddress returns the RFQ address for the given chain.
func (c Config) GetRFQAddress(chainID int) (string, error) {
// GetRFQAddressV1 returns the RFQ address for the given chain.
func (c Config) GetRFQAddressV1(chainID int) (*string, error) {
chainCfg, ok := c.Chains[chainID]
if !ok {
return nil, fmt.Errorf("chain config not found for chain %d", chainID)
}
return chainCfg.RFQAddressV1, nil
}

// GetRFQAddressV2 returns the RFQ address for the given chain.
func (c Config) GetRFQAddressV2(chainID int) (string, error) {
chainCfg, ok := c.Chains[chainID]
if !ok {
return "", fmt.Errorf("chain config not found for chain %d", chainID)
}
return chainCfg.RFQAddress, nil
return chainCfg.RFQAddressV2, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Standardize Return Types of GetRFQAddress Methods

GetRFQAddressV1 returns a pointer to string (*string, error), while GetRFQAddressV2 returns a string (string, error). This inconsistency might cause confusion and complicate error handling. Consider standardizing the return types of both methods to improve consistency and reduce potential errors.

Suggested Change:

Option 1: Have both methods return (*string, error):

// For GetRFQAddressV2
-func (c Config) GetRFQAddressV2(chainID int) (string, error) {
+func (c Config) GetRFQAddressV2(chainID int) (*string, error) {
     chainCfg, ok := c.Chains[chainID]
     if !ok {
-        return "", fmt.Errorf("chain config not found for chain %d", chainID)
+        return nil, fmt.Errorf("chain config not found for chain %d", chainID)
     }
-    return chainCfg.RFQAddressV2, nil
+    return &chainCfg.RFQAddressV2, nil
}

Option 2: Have both methods return (string, error) and adjust handling of optional values accordingly.

Committable suggestion was skipped due to low confidence.

}

const defaultDBSelectorIntervalSeconds = 1
Expand All @@ -115,7 +133,8 @@ func NewGuardConfigFromRelayer(relayerCfg relconfig.Config) Config {
}
for chainID, chainCfg := range relayerCfg.GetChains() {
cfg.Chains[chainID] = ChainConfig{
RFQAddress: chainCfg.RFQAddress,
RFQAddressV1: chainCfg.RFQAddressV1,
RFQAddressV2: chainCfg.RFQAddress,
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
Confirmations: chainCfg.FinalityConfirmations,
}
}
Expand Down
15 changes: 9 additions & 6 deletions services/rfq/guard/guarddb/base/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type PendingProvenModel struct {
Origin uint32
// RelayerAddress is the address of the relayer that called prove()
RelayerAddress string
// FastBridgeAddress is the address of the fast bridge contract
FastBridgeAddress string
// TransactionID is the transaction id of the event
TransactionID string `gorm:"column:transaction_id;primaryKey"`
// TxHash is the hash of the relay transaction on destination
Expand All @@ -49,12 +51,13 @@ type PendingProvenModel struct {
// FromPendingProven converts a quote request to an object that can be stored in the db.
func FromPendingProven(proven guarddb.PendingProven) PendingProvenModel {
return PendingProvenModel{
Origin: proven.Origin,
RelayerAddress: proven.RelayerAddress.Hex(),
TransactionID: hexutil.Encode(proven.TransactionID[:]),
TxHash: proven.TxHash.Hex(),
Status: proven.Status,
BlockNumber: proven.BlockNumber,
Origin: proven.Origin,
RelayerAddress: proven.RelayerAddress.Hex(),
FastBridgeAddress: proven.FastBridgeAddress.Hex(),
TransactionID: hexutil.Encode(proven.TransactionID[:]),
TxHash: proven.TxHash.Hex(),
Status: proven.Status,
BlockNumber: proven.BlockNumber,
}
}

Expand Down
13 changes: 7 additions & 6 deletions services/rfq/guard/guarddb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ type BridgeRequest struct {

// PendingProven is the pending proven object.
type PendingProven struct {
Origin uint32
RelayerAddress common.Address
TransactionID [32]byte
TxHash common.Hash
Status PendingProvenStatus
BlockNumber uint64
Origin uint32
RelayerAddress common.Address
FastBridgeAddress common.Address
TransactionID [32]byte
TxHash common.Hash
Status PendingProvenStatus
BlockNumber uint64
}

// PendingProvenStatus is the status of a quote request in the db.
Expand Down
188 changes: 155 additions & 33 deletions services/rfq/guard/service/guard.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"github.com/synapsecns/sanguine/ethergo/submitter"
omniClient "github.com/synapsecns/sanguine/services/omnirpc/client"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
"github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2"
"github.com/synapsecns/sanguine/services/rfq/guard/guardconfig"
"github.com/synapsecns/sanguine/services/rfq/guard/guarddb"
"github.com/synapsecns/sanguine/services/rfq/guard/guarddb/connect"
Expand All @@ -29,22 +30,23 @@

// Guard monitors calls to prove() and verifies them.
type Guard struct {
cfg guardconfig.Config
metrics metrics.Handler
db guarddb.Service
client omniClient.RPCClient
chainListeners map[int]listener.ContractListener
contracts map[int]*fastbridge.FastBridgeRef
txSubmitter submitter.TransactionSubmitter
otelRecorder iOtelRecorder
cfg guardconfig.Config
metrics metrics.Handler
db guarddb.Service
client omniClient.RPCClient
contractsV1 map[int]*fastbridge.FastBridgeRef
contractsV2 map[int]*fastbridgev2.FastBridgeV2Ref
listenersV1 map[int]listener.ContractListener
listenersV2 map[int]listener.ContractListener
txSubmitter submitter.TransactionSubmitter
otelRecorder iOtelRecorder
}

// NewGuard creates a new Guard.
//
//nolint:cyclop
func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfig.Config, txSubmitter submitter.TransactionSubmitter) (*Guard, error) {
omniClient := omniClient.NewOmnirpcClient(cfg.OmniRPCURL, metricHandler, omniClient.WithCaptureReqRes())
chainListeners := make(map[int]listener.ContractListener)

dbType, err := dbcommon.DBTypeFromString(cfg.Database.Type)
if err != nil {
Expand All @@ -55,37 +57,62 @@
return nil, fmt.Errorf("could not make db: %w", err)
}

contractsV1 := make(map[int]*fastbridge.FastBridgeRef)
contractsV2 := make(map[int]*fastbridgev2.FastBridgeV2Ref)
listenersV1 := make(map[int]listener.ContractListener)
listenersV2 := make(map[int]listener.ContractListener)

// setup chain listeners
contracts := make(map[int]*fastbridge.FastBridgeRef)
for chainID := range cfg.GetChains() {
rfqAddr, err := cfg.GetRFQAddress(chainID)
// setup v1
rfqAddrV1, err := cfg.GetRFQAddressV1(chainID)
if err != nil {
return nil, fmt.Errorf("could not get rfq address: %w", err)
}
if rfqAddrV1 != nil {
chainClient, err := omniClient.GetChainClient(ctx, chainID)
if err != nil {
return nil, fmt.Errorf("could not get chain client: %w", err)
}
contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(*rfqAddrV1), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create fast bridge contract: %w", err)
}
startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, fmt.Errorf("could not get deploy block: %w", err)
}
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(*rfqAddrV1), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
if err != nil {
return nil, fmt.Errorf("could not get chain listener: %w", err)
}
listenersV1[chainID] = chainListener
contractsV1[chainID] = contract
}
Comment on lines +60 to +91
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Add null check for v2 address and consider refactoring initialization

  1. The v2 initialization lacks a null check that exists for v1, which could cause issues if v2 contracts aren't deployed.
  2. There's significant duplication in the initialization logic between v1 and v2.

Apply this pattern for v2:

 rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
 if err != nil {
     return nil, fmt.Errorf("could not get rfq address: %w", err)
 }
+if rfqAddrV2 == "" {
+    continue
+}

Consider extracting the common initialization logic into a helper function:

func initializeContract[T any](
    ctx context.Context,
    chainID int,
    addr string,
    createContract func(common.Address) (T, error),
    listenerName string,
) (T, listener.ContractListener, error) {
    // Common initialization logic here
}

Also applies to: 93-115

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 60-64: services/rfq/guard/service/guard.go#L60-L64
Added lines #L60 - L64 were not covered by tests


[warning] 67-90: services/rfq/guard/service/guard.go#L67-L90
Added lines #L67 - L90 were not covered by tests

Comment on lines +68 to +91
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor initialization logic to eliminate duplication

The initialization code for V1 and V2 contracts is nearly identical, except for the contract versions and addresses. Extracting the shared logic into a helper function would reduce code duplication and improve maintainability.

Apply this refactor by creating a helper function:

func setupContract(
    ctx context.Context,
    chainID int,
    rfqAddr string,
    contractVersion string,
    omniClient omniClient.RPCClient,
    store guarddb.Service,
    metricHandler metrics.Handler,
) (listener.ContractListener, error) {
    chainClient, err := omniClient.GetChainClient(ctx, chainID)
    if err != nil {
        return nil, fmt.Errorf("could not get chain client: %w", err)
    }

    var contract interface{}
    var startBlock *big.Int

    switch contractVersion {
    case "v1":
        fastbridgeContract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient)
        if err != nil {
            return nil, fmt.Errorf("could not create fast bridge v1 contract: %w", err)
        }
        contract = fastbridgeContract
        startBlock, err = fastbridgeContract.DeployBlock(&bind.CallOpts{Context: ctx})
    case "v2":
        fastbridgeV2Contract, err := fastbridgev2.NewFastBridgeV2Ref(common.HexToAddress(rfqAddr), chainClient)
        if err != nil {
            return nil, fmt.Errorf("could not create fast bridge v2 contract: %w", err)
        }
        contract = fastbridgeV2Contract
        startBlock, err = fastbridgeV2Contract.DeployBlock(&bind.CallOpts{Context: ctx})
    default:
        return nil, fmt.Errorf("unknown contract version: %s", contractVersion)
    }

    if err != nil {
        return nil, fmt.Errorf("could not get deploy block: %w", err)
    }

    listenerName := "guard"
    if contractVersion == "v2" {
        listenerName = "guardV2"
    }

    chainListener, err := listener.NewChainListener(
        chainClient,
        store,
        common.HexToAddress(rfqAddr),
        uint64(startBlock.Int64()),
        metricHandler,
        listener.WithName(listenerName),
    )
    if err != nil {
        return nil, fmt.Errorf("could not get chain listener: %w", err)
    }

    return chainListener, nil
}

Then, refactor the original code to use this helper function.

Also applies to: 94-115


// setup v2
rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
if err != nil {
return nil, fmt.Errorf("could not get rfq address: %w", err)
}
chainClient, err := omniClient.GetChainClient(ctx, chainID)
if err != nil {
return nil, fmt.Errorf("could not get chain client: %w", err)
}

contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient)
contract, err := fastbridgev2.NewFastBridgeV2Ref(common.HexToAddress(rfqAddrV2), chainClient)
Comment on lines +94 to +102
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for V2 RFQ address

The V2 initialization does not check if rfqAddrV2 is empty or nil before proceeding. This could lead to runtime errors if the V2 address is not set. Add a null check similar to the V1 initialization to ensure robustness.

Apply this diff to add the null check:

 rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
 if err != nil {
     return nil, fmt.Errorf("could not get rfq address: %w", err)
+}
+if rfqAddrV2 == "" {
+    continue
 }
 chainClient, err := omniClient.GetChainClient(ctx, chainID)

Committable suggestion skipped: line range outside the PR's diff.

if err != nil {
return nil, fmt.Errorf("could not create fast bridge contract: %w", err)
}
startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, fmt.Errorf("could not get deploy block: %w", err)
}
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddr), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("could not get chain listener: %w", err)
}
chainListeners[chainID] = chainListener

// setup FastBridge contract on this chain
contracts[chainID], err = fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create bridge contract: %w", err)
}
listenersV2[chainID] = chainListener
contractsV2[chainID] = contract
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for v2 address

The v2 contract initialization assumes rfqAddrV2 is always non-empty. Consider adding a null check similar to v1 to handle cases where v2 contracts might not be deployed yet.

Apply this pattern:

 rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
 if err != nil {
     return nil, fmt.Errorf("could not get rfq address: %w", err)
 }
+if rfqAddrV2 == "" {
+    continue
+}
 chainClient, err := omniClient.GetChainClient(ctx, chainID)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// setup v2
rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
if err != nil {
return nil, fmt.Errorf("could not get rfq address: %w", err)
}
chainClient, err := omniClient.GetChainClient(ctx, chainID)
if err != nil {
return nil, fmt.Errorf("could not get chain client: %w", err)
}
contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient)
contract, err := fastbridgev2.NewFastBridgeV2Ref(common.HexToAddress(rfqAddrV2), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create fast bridge contract: %w", err)
}
startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, fmt.Errorf("could not get deploy block: %w", err)
}
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddr), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
if err != nil {
return nil, fmt.Errorf("could not get chain listener: %w", err)
}
chainListeners[chainID] = chainListener
// setup FastBridge contract on this chain
contracts[chainID], err = fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create bridge contract: %w", err)
}
listenersV2[chainID] = chainListener
contractsV2[chainID] = contract
// setup v2
rfqAddrV2, err := cfg.GetRFQAddressV2(chainID)
if err != nil {
return nil, fmt.Errorf("could not get rfq address: %w", err)
}
if rfqAddrV2 == "" {
continue
}
chainClient, err := omniClient.GetChainClient(ctx, chainID)
if err != nil {
return nil, fmt.Errorf("could not get chain client: %w", err)
}
contract, err := fastbridgev2.NewFastBridgeV2Ref(common.HexToAddress(rfqAddrV2), chainClient)
if err != nil {
return nil, fmt.Errorf("could not create fast bridge contract: %w", err)
}
startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, fmt.Errorf("could not get deploy block: %w", err)
}
chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard"))
if err != nil {
return nil, fmt.Errorf("could not get chain listener: %w", err)
}
listenersV2[chainID] = chainListener
contractsV2[chainID] = contract

}

// build submitter from config if one is not supplied
Expand All @@ -103,14 +130,16 @@
}

return &Guard{
cfg: cfg,
metrics: metricHandler,
db: store,
client: omniClient,
chainListeners: chainListeners,
contracts: contracts,
txSubmitter: txSubmitter,
otelRecorder: otelRecorder,
cfg: cfg,
metrics: metricHandler,
db: store,
client: omniClient,
contractsV1: contractsV1,
contractsV2: contractsV2,
listenersV1: listenersV1,
listenersV2: listenersV2,
txSubmitter: txSubmitter,
otelRecorder: otelRecorder,
}, nil
}

Expand Down Expand Up @@ -173,10 +202,26 @@
for chainID := range g.cfg.GetChains() {
//nolint: copyloopvar
chainID := chainID // capture loop variable

// only run v1 if it is set
v1Addr, err := g.cfg.GetRFQAddressV1(chainID)
if err != nil {
return fmt.Errorf("could not get rfq address v1: %w", err)
}
if v1Addr != nil {
group.Go(func() error {
err := g.runChainIndexerV1(ctx, chainID)
if err != nil {
return fmt.Errorf("could not runChainIndexer chain indexer for chain %d [v1]: %w", chainID, err)
}
return nil
})
}

group.Go(func() error {
err := g.runChainIndexer(ctx, chainID)
err := g.runChainIndexerV2(ctx, chainID)
if err != nil {
return fmt.Errorf("could not runChainIndexer chain indexer for chain %d: %w", chainID, err)
return fmt.Errorf("could not runChainIndexer chain indexer for chain %d [v2]: %w", chainID, err)
}
return nil
})
Expand All @@ -191,8 +236,8 @@
}

//nolint:cyclop
func (g Guard) runChainIndexer(ctx context.Context, chainID int) (err error) {
chainListener := g.chainListeners[chainID]
func (g Guard) runChainIndexerV1(ctx context.Context, chainID int) (err error) {
chainListener := g.listenersV1[chainID]

parser, err := fastbridge.NewParser(chainListener.Address())
if err != nil {
Expand Down Expand Up @@ -247,6 +292,75 @@
return nil
}

//nolint:cyclop
func (g Guard) runChainIndexerV2(ctx context.Context, chainID int) (err error) {
chainListener := g.listenersV2[chainID]

parser, err := fastbridgev2.NewParser(chainListener.Address())
if err != nil {
return fmt.Errorf("could not parse: %w", err)
}

err = chainListener.Listen(ctx, func(parentCtx context.Context, log types.Log) (err error) {
et, parsedEvent, ok := parser.ParseEvent(log)
// handle unknown event
if !ok {
if len(log.Topics) != 0 {
logger.Warnf("unknown event %s", log.Topics[0])
}
return nil
}

ctx, span := g.metrics.Tracer().Start(parentCtx, fmt.Sprintf("handleLog-%s", et), trace.WithAttributes(
attribute.String(metrics.TxHash, log.TxHash.String()),
attribute.Int(metrics.Origin, chainID),
attribute.String(metrics.Contract, log.Address.String()),
attribute.String("block_hash", log.BlockHash.String()),
attribute.Int64("block_number", int64(log.BlockNumber)),

Check failure on line 319 in services/rfq/guard/service/guard.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

G115: integer overflow conversion uint64 -> int64 (gosec)
))

defer func() {
metrics.EndSpanWithErr(span, err)
}()

switch event := parsedEvent.(type) {
case *fastbridgev2.FastBridgeV2BridgeRequested:
v1Event := &fastbridge.FastBridgeBridgeRequested{
TransactionId: event.TransactionId,
Sender: event.Sender,
Request: event.Request,
DestChainId: event.DestChainId,
OriginToken: event.OriginToken,
DestToken: event.DestToken,
DestAmount: event.DestAmount,
SendChainGas: event.SendChainGas,
Raw: event.Raw,
}
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
err = g.handleBridgeRequestedLog(ctx, v1Event, chainID)
if err != nil {
return fmt.Errorf("could not handle request: %w", err)
}
// following events match ABIs exactly, so no need to differentiate
case *fastbridge.FastBridgeBridgeProofProvided:
err = g.handleProofProvidedLog(ctx, event, chainID)
if err != nil {
return fmt.Errorf("could not handle request: %w", err)
}
case *fastbridge.FastBridgeBridgeProofDisputed:
err = g.handleProofDisputedLog(ctx, event)
if err != nil {
return fmt.Errorf("could not handle request: %w", err)
}
}

return nil
})
if err != nil {
return fmt.Errorf("listener failed: %w", err)
}
return nil
}

func (g *Guard) processDB(ctx context.Context) (err error) {
provens, err := g.db.GetPendingProvensByStatus(ctx, guarddb.ProveCalled)
if err != nil {
Expand All @@ -262,3 +376,11 @@

return nil
}

func (g *Guard) isV2Address(chainID int, addr common.Address) bool {
rfqAddr, err := g.cfg.GetRFQAddressV2(chainID)
if err != nil {
return false
}
return addr == common.HexToAddress(rfqAddr)
}
Comment on lines +387 to +393
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider caching the v2 address lookup

The isV2Address function performs a config lookup and address comparison on every call. Consider caching the v2 addresses in a map during initialization to improve performance.

Example implementation:

type Guard struct {
    // ... existing fields ...
    v2AddressCache map[int]common.Address
}

func (g *Guard) isV2Address(chainID int, addr common.Address) bool {
    if cachedAddr, ok := g.v2AddressCache[chainID]; ok {
        return addr == cachedAddr
    }
    return false
}

Loading
Loading