diff --git a/bridge/setu/processor/checkpoint.go b/bridge/setu/processor/checkpoint.go index 8acdf364..cb71a1eb 100644 --- a/bridge/setu/processor/checkpoint.go +++ b/bridge/setu/processor/checkpoint.go @@ -10,6 +10,7 @@ import ( "math" "math/big" "strconv" + "strings" "sync" "time" @@ -499,6 +500,10 @@ func (cp *CheckpointProcessor) nextExpectedCheckpoint(checkpointContext *Checkpo ) } + if !cp.filterEthCrossChain(start, end, rootChain, checkpointParams.MaxCheckpointLength) { + end = start + } + // Handle when block producers go down if end == 0 || end == start || (0 < diff && diff < checkpointParams.AvgCheckpointLength) { cp.Logger.Debug("Fetching last header block to calculate time") @@ -528,6 +533,33 @@ func (cp *CheckpointProcessor) nextExpectedCheckpoint(checkpointContext *Checkpo }), nil } +func (cp *CheckpointProcessor) filterEthCrossChain(start uint64, end uint64, rootChain string, + maxCheckpointLengthParam uint64, +) bool { + isOpen, rootChainIsOpen, maxLength := cp.getDynamicCheckpointProposal(rootChain) + + if !isOpen || !rootChainIsOpen { + return true + } + + if maxCheckpointLengthParam < uint64(maxLength) { + cp.Logger.Error("proposal feature-dynamic-checkpoint maxlength is too long", + "maxLength", maxLength, "MaxCheckpointLength", maxCheckpointLengthParam) + + return true + } + + if end-start+1 >= uint64(maxLength) { + return true + } + + if cp.checkHasCrossChain(start, end, rootChain) { + return true + } + + return false +} + // sendCheckpointToHeimdall - creates checkpoint msg and broadcasts to heimdall func (cp *CheckpointProcessor) createAndSendCheckpointToHeimdall(checkpointContext *CheckpointContext, start, end uint64, rootChain string) error { cp.Logger.Debug("Initiating checkpoint to Heimdall", "root", rootChain, "start", start, "end", end) @@ -985,3 +1017,91 @@ func (cp *CheckpointProcessor) getCheckpointContext(rootChain string) (*Checkpoi CheckpointParams: checkpointParams, }, nil } + +func (cp *CheckpointProcessor) checkHasCrossChain(start uint64, end uint64, rootChain string) bool { + addrs, canUse := cp.getAddress(rootChain) + if !canUse { + cp.Logger.Error("mapToken address can't use") + + return true + } + + if len(addrs) == 0 { + cp.Logger.Error("mapToken address can't use: len=0") + + return true + } + + topics := util.GetWithDrawToTopics() + + if len(topics) == 0 { + cp.Logger.Error("topics can't use: len=0") + + return true + } + + logs, err := cp.contractConnector.GetLogs(big.NewInt(int64(start)), big.NewInt(int64(end)), addrs, topics) + if err != nil { + cp.Logger.Error("Error while GetLogs", "error", err) + + return true + } + + cp.Logger.Info("checkHasCrossChain", "start", start, "end", end, "addrLen", len(addrs), "logsLen", len(logs)) + + return len(logs) != 0 +} + +func (cp *CheckpointProcessor) getAddress(rootChain string) ([]common.Address, bool) { + eventProcessor := util.NewTokenMapProcessor(cp.cliCtx, cp.storageClient) + + nodeStatus, err := helper.GetNodeStatus(cp.cliCtx) + if err != nil { + cp.Logger.Error("Error while fetching heimdall node status", "error", err) + + return nil, false + } + + toBlock := nodeStatus.SyncInfo.LatestBlockHeight + + done, err := eventProcessor.IsInitializationDoneWithBlock(toBlock) + if err != nil { + cp.Logger.Error("Error while fetching token map in IsInitializationDoneWithBlock", "toBlock", toBlock, "error", err) + + return nil, false + } + + if !done { + cp.Logger.Error("Not done while fetching token map in IsInitializationDoneWithBlock ", "toBlock", toBlock) + + return nil, false + } + + mlist, err := eventProcessor.GetTokenMapByRootType(rootChain) + if err != nil { + cp.Logger.Error("Error while fetching token map in GetTokenMapByRootType", "rootChain", rootChain, "error", err) + + return nil, false + } + + cp.Logger.Info("getAddress", "rootChain", rootChain, "mlistLen", len(mlist), "toBlock", toBlock) + + retSlice := make([]common.Address, 0, len(mlist)) + + for _, item := range mlist { + retSlice = append(retSlice, common.HexToAddress(item.ChildToken)) + } + + return retSlice, true +} + +func (cp *CheckpointProcessor) getDynamicCheckpointProposal(rootType string) (bool, bool, int) { + fea, err := util.GetDynamicCheckpointFeature(cp.cliCtx) + if err != nil { + cp.Logger.Error("Error while fetching dynamic checkpoint feature", "error", err) + + return false, false, 0 + } + + return fea.IsOpen, fea.IntConf[strings.ToLower(rootType)] != 0, fea.IntConf["maxLength"] +} diff --git a/bridge/setu/util/common.go b/bridge/setu/util/common.go index 63e1e67f..7f2d4457 100644 --- a/bridge/setu/util/common.go +++ b/bridge/setu/util/common.go @@ -12,6 +12,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + stakingTypes "github.com/maticnetwork/heimdall/staking/types" mLog "github.com/RichardKnop/machinery/v1/log" @@ -69,8 +72,12 @@ const ( BridgeDBFlag = "bridge-db" ProposersURLSizeLimit = 100 + + WithdrawToEventSig = "0x67b714876402c93362735688659e2283b4a37fb21bab24bc759ca759ae851fd8" ) +var withDrawToTopics = [][]string{{WithdrawToEventSig}} + var ( logger log.Logger loggerOnce sync.Once @@ -533,6 +540,36 @@ func GetValidatorNonce(cliCtx cliContext.CLIContext, validatorID uint64) (uint64 return validator.Nonce, result.Height, nil } +func GetWithDrawToTopics() [][]common.Hash { + return getTopics(withDrawToTopics) +} + +func getTopics(topicStr [][]string) [][]common.Hash { + ret := make([][]common.Hash, len(topicStr)) + + for i, topics := range topicStr { + for _, topic := range topics { + topicByte, err := hexutil.Decode(topic) + if err != nil { + logger.Error("Error while decoding topic", "error", err) + + return nil + } + + var h common.Hash + + copy(h[:], topicByte) + ret[i] = append(ret[i], h) + } + } + + return ret +} + +func GetDynamicCheckpointFeature(cliCtx cliContext.CLIContext) (*featureManagerTypes.PlainFeatureData, error) { + return GetTargetFeatureConfig(cliCtx, featureManagerTypes.DynamicCheckpoint) +} + // GetTargetFeatureConfig return target feature config. func GetTargetFeatureConfig( cliCtx cliContext.CLIContext, feature string, diff --git a/featuremanager/keeper.go b/featuremanager/keeper.go index a449c2b1..2ceb1023 100644 --- a/featuremanager/keeper.go +++ b/featuremanager/keeper.go @@ -62,6 +62,7 @@ func (k Keeper) addFeature(feature string) { func (k Keeper) RegistreFeature() { // all new type of features should be registered here. k.addFeature("feature-x") + k.addFeature(types.DynamicCheckpoint) } func (k Keeper) HasFeature(feature string) bool { diff --git a/featuremanager/types/keys.go b/featuremanager/types/keys.go index 02df84ca..54650a2a 100644 --- a/featuremanager/types/keys.go +++ b/featuremanager/types/keys.go @@ -16,3 +16,7 @@ const ( // DefaultParamspace default name for parameter store. DefaultParamspace = ModuleName ) + +const ( + DynamicCheckpoint = "DynamicCheckpoint" +) diff --git a/helper/call.go b/helper/call.go index 31ca59d6..782fe4af 100644 --- a/helper/call.go +++ b/helper/call.go @@ -11,6 +11,8 @@ import ( "strconv" "strings" + "github.com/ethereum/go-ethereum" + "github.com/maticnetwork/heimdall/tron" "github.com/ethereum/go-ethereum/accounts/abi" @@ -462,6 +464,22 @@ func (c *ContractCaller) GetBlockNumberFromTxHash(tx common.Hash) (*big.Int, err return blkNum, nil } +func (c *ContractCaller) GetLogs(fromBlock *big.Int, toBlock *big.Int, addrs []common.Address, + topics [][]common.Hash, +) ([]ethTypes.Log, error) { + logs, err := c.MaticChainClient.FilterLogs(context.Background(), ethereum.FilterQuery{ + FromBlock: fromBlock, + ToBlock: toBlock, + Addresses: addrs, + Topics: topics, + }) + if err != nil { + return nil, err + } + + return logs, nil +} + // GetConfirmedTxReceipt returns confirmed tx receipt func (c *ContractCaller) GetConfirmedTxReceipt(tx common.Hash, requiredConfirmations uint64, rootChain string) (*ethTypes.Receipt, error) {