From 4014000f5be70ec3d5e624c8c5b6d57e316fca03 Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Mon, 4 Apr 2022 12:21:58 +0400 Subject: [PATCH] Rework event handlers --- config/config.go | 14 ++++ contract/abi/abi.go | 55 ++++++++++++++ contract/{constants => abi}/amb.json | 0 .../{constants => abi}/erc_to_native.json | 0 contract/constants/abi.go | 28 ------- contract/contract.go | 14 ++-- monitor/handlers.go | 4 +- monitor/monitor.go | 76 ++++++++++--------- 8 files changed, 121 insertions(+), 70 deletions(-) create mode 100644 contract/abi/abi.go rename contract/{constants => abi}/amb.json (100%) rename contract/{constants => abi}/erc_to_native.json (100%) delete mode 100644 contract/constants/abi.go diff --git a/config/config.go b/config/config.go index 5a07b9f..d547841 100644 --- a/config/config.go +++ b/config/config.go @@ -123,6 +123,20 @@ func (cfg *Config) init() error { return nil } +func (cfg *BridgeSideConfig) ContractAddresses(fromBlock, toBlock uint) []common.Address { + addresses := []common.Address{cfg.Address, cfg.ValidatorContractAddress} + for _, token := range cfg.ErcToNativeTokens { + if token.StartBlock > 0 && toBlock < token.StartBlock { + continue + } + if token.EndBlock > 0 && fromBlock > token.EndBlock { + continue + } + addresses = append(addresses, token.Address) + } + return addresses +} + func ReadConfig() (*Config, error) { cfg := new(Config) err := readYamlConfig(cfg) diff --git a/contract/abi/abi.go b/contract/abi/abi.go new file mode 100644 index 0000000..cc73cd8 --- /dev/null +++ b/contract/abi/abi.go @@ -0,0 +1,55 @@ +package abi + +import ( + _ "embed" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +//go:embed amb.json +var ambJsonABI string + +//go:embed erc_to_native.json +var etnJsonABI string + +var AMB, ERC_TO_NATIVE abi.ABI + +const ( + UserRequestForSignature = "event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData)" + LegacyUserRequestForSignature = "event UserRequestForSignature(bytes encodedData)" + UserRequestForAffirmation = "event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData)" + LegacyUserRequestForAffirmation = "event UserRequestForAffirmation(bytes encodedData)" + UserRequestForInformation = "event UserRequestForInformation(bytes32 indexed messageId, bytes32 indexed requestSelector, address indexed sender, bytes data)" + SignedForUserRequest = "event SignedForUserRequest(address indexed signer, bytes32 messageHash)" + SignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 messageHash)" + SignedForInformation = "event SignedForInformation(address indexed signer, bytes32 indexed messageId)" + CollectedSignatures = "event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash, uint256 NumberOfCollectedSignatures)" + AffirmationCompleted = "event AffirmationCompleted(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)" + LegacyAffirmationCompleted = "event AffirmationCompleted(address sender, address executor, bytes32 messageId, bool status)" + RelayedMessage = "event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)" + LegacyRelayedMessage = "event RelayedMessage(address sender, address executor, bytes32 messageId, bool status)" + InformationRetrieved = "event InformationRetrieved(bytes32 indexed messageId, bool status, bool callbackStatus)" + + ErcToNativeUserRequestForSignature = "event UserRequestForSignature(address recipient, uint256 value)" + ErcToNativeTransfer = "event Transfer(address indexed from, address indexed to, uint256 value)" + ErcToNativeRelayedMessage = "event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash)" + ErcToNativeUserRequestForAffirmation = "event UserRequestForAffirmation(address recipient, uint256 value)" + ErcToNativeAffirmationCompleted = "event AffirmationCompleted(address recipient, uint256 value, bytes32 transactionHash)" + ErcToNativeSignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 transactionHash)" + + ValidatorAdded = "event ValidatorAdded(address indexed validator)" + ValidatorRemoved = "event ValidatorRemoved(address indexed validator)" +) + +func init() { + var err error + AMB, err = abi.JSON(strings.NewReader(ambJsonABI)) + if err != nil { + panic(err) + } + ERC_TO_NATIVE, err = abi.JSON(strings.NewReader(etnJsonABI)) + if err != nil { + panic(err) + } +} diff --git a/contract/constants/amb.json b/contract/abi/amb.json similarity index 100% rename from contract/constants/amb.json rename to contract/abi/amb.json diff --git a/contract/constants/erc_to_native.json b/contract/abi/erc_to_native.json similarity index 100% rename from contract/constants/erc_to_native.json rename to contract/abi/erc_to_native.json diff --git a/contract/constants/abi.go b/contract/constants/abi.go deleted file mode 100644 index 2c827e6..0000000 --- a/contract/constants/abi.go +++ /dev/null @@ -1,28 +0,0 @@ -package constants - -import ( - _ "embed" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" -) - -//go:embed amb.json -var ambJsonABI string - -//go:embed erc_to_native.json -var etnJsonABI string - -var AMB, ERC_TO_NATIVE abi.ABI - -func init() { - var err error - AMB, err = abi.JSON(strings.NewReader(ambJsonABI)) - if err != nil { - panic(err) - } - ERC_TO_NATIVE, err = abi.JSON(strings.NewReader(etnJsonABI)) - if err != nil { - panic(err) - } -} diff --git a/contract/contract.go b/contract/contract.go index 159c5e4..efce060 100644 --- a/contract/contract.go +++ b/contract/contract.go @@ -3,7 +3,6 @@ package contract import ( "amb-monitor/entity" "amb-monitor/ethclient" - "bytes" "context" "fmt" @@ -22,9 +21,12 @@ func NewContract(client *ethclient.Client, addr common.Address, abi abi.ABI) *Co return &Contract{addr, client, abi} } -func (c *Contract) HasEvent(event string) bool { - _, ok := c.abi.Events[event] - return ok +func (c *Contract) AllEvents() map[string]bool { + events := make(map[string]bool, len(c.abi.Events)) + for _, event := range c.abi.Events { + events[event.String()] = true + } + return events } func (c *Contract) ValidatorContractAddress(ctx context.Context) (common.Address, error) { @@ -59,7 +61,7 @@ func (c *Contract) ParseLog(log *entity.Log) (string, map[string]interface{}, er var event *abi.Event var indexed abi.Arguments for _, e := range c.abi.Events { - if bytes.Equal(e.ID.Bytes(), log.Topic0.Bytes()) { + if e.ID == *log.Topic0 { indexed = Indexed(e.Inputs) if len(indexed) == len(topics) { event = &e @@ -79,7 +81,7 @@ func (c *Contract) ParseLog(log *entity.Log) (string, map[string]interface{}, er if err := abi.ParseTopicsIntoMap(m, indexed, topics); err != nil { return "", nil, fmt.Errorf("can't unpack topics: %w", err) } - return event.Name, m, nil + return event.String(), m, nil } func Indexed(args abi.Arguments) abi.Arguments { diff --git a/monitor/handlers.go b/monitor/handlers.go index cc8fedc..52dd43d 100644 --- a/monitor/handlers.go +++ b/monitor/handlers.go @@ -2,7 +2,7 @@ package monitor import ( "amb-monitor/config" - "amb-monitor/contract/constants" + "amb-monitor/contract/abi" "amb-monitor/entity" "amb-monitor/ethclient" "amb-monitor/repository" @@ -77,7 +77,7 @@ func (p *BridgeEventHandler) HandleErcToNativeTransfer(ctx context.Context, log return fmt.Errorf("failed to get transaction receipt by hash %s: %w", log.TransactionHash, err) } for _, l := range receipt.Logs { - if len(l.Topics) > 0 && l.Topics[0] == constants.ERC_TO_NATIVE.Events["UserRequestForAffirmation"].ID { + if len(l.Topics) > 0 && l.Topics[0] == abi.ERC_TO_NATIVE.Events["UserRequestForAffirmation"].ID { return nil } } diff --git a/monitor/monitor.go b/monitor/monitor.go index 1cd6454..920a017 100644 --- a/monitor/monitor.go +++ b/monitor/monitor.go @@ -3,7 +3,7 @@ package monitor import ( "amb-monitor/config" "amb-monitor/contract" - "amb-monitor/contract/constants" + "amb-monitor/contract/abi" "amb-monitor/db" "amb-monitor/entity" "amb-monitor/ethclient" @@ -63,11 +63,11 @@ func newContractMonitor(ctx context.Context, logger logging.Logger, repo *reposi if err != nil { return nil, fmt.Errorf("failed to start eth client: %w", err) } - abi := constants.AMB + contractAbi := abi.AMB if bridgeCfg.IsErcToNative { - abi = constants.ERC_TO_NATIVE + contractAbi = abi.ERC_TO_NATIVE } - bridgeContract := contract.NewContract(client, cfg.Address, abi) + bridgeContract := contract.NewContract(client, cfg.Address, contractAbi) if cfg.ValidatorContractAddress == (common.Address{}) { cfg.ValidatorContractAddress, err = bridgeContract.ValidatorContractAddress(ctx) if err != nil { @@ -137,32 +137,45 @@ func NewMonitor(ctx context.Context, logger logging.Logger, dbConn *db.DB, repo } handlers := NewBridgeEventHandler(repo, cfg.ID, homeMonitor.client, foreignMonitor.client, cfg) if cfg.IsErcToNative { - homeMonitor.eventHandlers["UserRequestForSignature"] = handlers.HandleErcToNativeUserRequestForSignature - homeMonitor.eventHandlers["SignedForAffirmation"] = handlers.HandleErcToNativeSignedForAffirmation - homeMonitor.eventHandlers["AffirmationCompleted"] = handlers.HandleErcToNativeAffirmationCompleted - foreignMonitor.eventHandlers["UserRequestForAffirmation"] = handlers.HandleErcToNativeUserRequestForAffirmation - foreignMonitor.eventHandlers["Transfer"] = handlers.HandleErcToNativeTransfer - foreignMonitor.eventHandlers["RelayedMessage"] = handlers.HandleErcToNativeRelayedMessage + homeMonitor.eventHandlers[abi.ErcToNativeUserRequestForSignature] = handlers.HandleErcToNativeUserRequestForSignature + homeMonitor.eventHandlers[abi.ErcToNativeSignedForAffirmation] = handlers.HandleErcToNativeSignedForAffirmation + homeMonitor.eventHandlers[abi.ErcToNativeAffirmationCompleted] = handlers.HandleErcToNativeAffirmationCompleted + foreignMonitor.eventHandlers[abi.ErcToNativeUserRequestForAffirmation] = handlers.HandleErcToNativeUserRequestForAffirmation + foreignMonitor.eventHandlers[abi.ErcToNativeTransfer] = handlers.HandleErcToNativeTransfer + foreignMonitor.eventHandlers[abi.ErcToNativeRelayedMessage] = handlers.HandleErcToNativeRelayedMessage } else { - homeMonitor.eventHandlers["UserRequestForSignature"] = handlers.HandleUserRequestForSignature - homeMonitor.eventHandlers["UserRequestForSignature0"] = handlers.HandleLegacyUserRequestForSignature - homeMonitor.eventHandlers["SignedForAffirmation"] = handlers.HandleSignedForUserRequest - homeMonitor.eventHandlers["AffirmationCompleted"] = handlers.HandleAffirmationCompleted - homeMonitor.eventHandlers["AffirmationCompleted0"] = handlers.HandleAffirmationCompleted - homeMonitor.eventHandlers["UserRequestForInformation"] = handlers.HandleUserRequestForInformation - homeMonitor.eventHandlers["SignedForInformation"] = handlers.HandleSignedForInformation - homeMonitor.eventHandlers["InformationRetrieved"] = handlers.HandleInformationRetrieved - foreignMonitor.eventHandlers["UserRequestForAffirmation"] = handlers.HandleUserRequestForAffirmation - foreignMonitor.eventHandlers["UserRequestForAffirmation0"] = handlers.HandleLegacyUserRequestForAffirmation - foreignMonitor.eventHandlers["RelayedMessage"] = handlers.HandleRelayedMessage - foreignMonitor.eventHandlers["RelayedMessage0"] = handlers.HandleRelayedMessage + homeMonitor.eventHandlers[abi.UserRequestForSignature] = handlers.HandleUserRequestForSignature + homeMonitor.eventHandlers[abi.LegacyUserRequestForSignature] = handlers.HandleLegacyUserRequestForSignature + homeMonitor.eventHandlers[abi.SignedForAffirmation] = handlers.HandleSignedForUserRequest + homeMonitor.eventHandlers[abi.AffirmationCompleted] = handlers.HandleAffirmationCompleted + homeMonitor.eventHandlers[abi.LegacyAffirmationCompleted] = handlers.HandleAffirmationCompleted + homeMonitor.eventHandlers[abi.UserRequestForInformation] = handlers.HandleUserRequestForInformation + homeMonitor.eventHandlers[abi.SignedForInformation] = handlers.HandleSignedForInformation + homeMonitor.eventHandlers[abi.InformationRetrieved] = handlers.HandleInformationRetrieved + foreignMonitor.eventHandlers[abi.UserRequestForAffirmation] = handlers.HandleUserRequestForAffirmation + foreignMonitor.eventHandlers[abi.LegacyUserRequestForAffirmation] = handlers.HandleLegacyUserRequestForAffirmation + foreignMonitor.eventHandlers[abi.RelayedMessage] = handlers.HandleRelayedMessage + foreignMonitor.eventHandlers[abi.LegacyRelayedMessage] = handlers.HandleRelayedMessage + } + homeMonitor.eventHandlers[abi.SignedForUserRequest] = handlers.HandleSignedForUserRequest + homeMonitor.eventHandlers[abi.CollectedSignatures] = handlers.HandleCollectedSignatures + homeMonitor.eventHandlers[abi.ValidatorAdded] = handlers.HandleValidatorAdded + homeMonitor.eventHandlers[abi.ValidatorRemoved] = handlers.HandleValidatorRemoved + foreignMonitor.eventHandlers[abi.ValidatorAdded] = handlers.HandleValidatorAdded + foreignMonitor.eventHandlers[abi.ValidatorRemoved] = handlers.HandleValidatorRemoved + + homeEvents := homeMonitor.contract.AllEvents() + foreignEvents := homeMonitor.contract.AllEvents() + for e := range homeMonitor.eventHandlers { + if !homeEvents[e] { + return nil, fmt.Errorf("home side contract does not have %s event in its ABI", e) + } + } + for e := range foreignMonitor.eventHandlers { + if !foreignEvents[e] { + return nil, fmt.Errorf("foreign side contract does not have %s event in its ABI", e) + } } - homeMonitor.eventHandlers["SignedForUserRequest"] = handlers.HandleSignedForUserRequest - homeMonitor.eventHandlers["CollectedSignatures"] = handlers.HandleCollectedSignatures - homeMonitor.eventHandlers["ValidatorAdded"] = handlers.HandleValidatorAdded - homeMonitor.eventHandlers["ValidatorRemoved"] = handlers.HandleValidatorRemoved - foreignMonitor.eventHandlers["ValidatorAdded"] = handlers.HandleValidatorAdded - foreignMonitor.eventHandlers["ValidatorRemoved"] = handlers.HandleValidatorRemoved return &Monitor{ cfg: cfg, logger: logger, @@ -211,12 +224,7 @@ func (m *ContractMonitor) LoadUnprocessedLogs(ctx context.Context, fromBlock, to var logs []*entity.Log for { var err error - addresses := []common.Address{m.cfg.Address, m.cfg.ValidatorContractAddress} - if m.bridgeCfg.IsErcToNative { - for _, token := range m.bridgeCfg.Foreign.ErcToNativeTokens { - addresses = append(addresses, token.Address) - } - } + addresses := m.cfg.ContractAddresses(fromBlock, toBlock) logs, err = m.repo.Logs.FindByBlockRange(ctx, m.client.ChainID, addresses, fromBlock, toBlock) if err != nil { m.logger.WithError(err).Error("can't find unprocessed logs in block range")