Skip to content
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
40 changes: 35 additions & 5 deletions bridge/setu/processor/checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,16 +848,36 @@ func (cp *CheckpointProcessor) checkIfNoAckIsRequired(checkpointContext *Checkpo
currentTime := time.Now().UTC()

timeDiff := currentTime.Sub(checkpointCreationTime)
if timeDiff.Seconds() >= helper.GetConfig().CheckpointerPollInterval.Seconds() && index == 0 {
index = math.Floor(timeDiff.Seconds() / helper.GetConfig().CheckpointerPollInterval.Seconds())

// checkpoint params
checkpointParams := checkpointContext.CheckpointParams

var checkpointPollInterval time.Duration
if checkpointParams.CheckpointPollInterval > 0 {
checkpointPollInterval = checkpointParams.CheckpointPollInterval
} else {
checkpointPollInterval = helper.GetConfig().CheckpointerPollInterval
}

if index == 0 {
var checkpointTimeout time.Duration
isOpen, tronMaxLength, err := cp.getTronDynamicCheckpointProposalWithErr()
if err != nil {
cp.Logger.Error("failed to check if no ack is required. Error while fetching dynamic checkpoint feature", "error", err)
return false, uint64(index)
}
if isOpen {
checkpointTimeout, _ = helper.CalcCheckpointTimeout(tronMaxLength, checkpointPollInterval)
} else {
checkpointTimeout = checkpointPollInterval
}

// checkpoint params
checkpointParams := checkpointContext.CheckpointParams
if timeDiff.Seconds() >= checkpointTimeout.Seconds() && index == 0 {
index = math.Floor(timeDiff.Seconds() / checkpointTimeout.Seconds())
}

if index == 0 {
return false, uint64(index)
}

// check if difference between no-ack time and current time
lastNoAck := cp.getLastNoAckTime()
Expand Down Expand Up @@ -1096,3 +1116,13 @@ func (cp *CheckpointProcessor) getDynamicCheckpointProposal(rootType string) (bo

return fea.IsOpen, fea.IntConf[strings.ToLower(rootType)] != 0, fea.IntConf["maxLength"]
}

func (cp *CheckpointProcessor) getTronDynamicCheckpointProposalWithErr() (bool, int, error) {
fea, err := util.GetTronDynamicCheckpointFeature(cp.cliCtx)
if err != nil {
cp.Logger.Error("Error while fetching dynamic checkpoint feature", "error", err)

return false, 0, err
}
return fea.IsOpen, fea.IntConf["maxLength"], err
}
4 changes: 4 additions & 0 deletions bridge/setu/util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ func GetDynamicCheckpointFeature(cliCtx cliContext.CLIContext) (*featureManagerT
return GetTargetFeatureConfig(cliCtx, featureManagerTypes.DynamicCheckpoint)
}

func GetTronDynamicCheckpointFeature(cliCtx cliContext.CLIContext) (*featureManagerTypes.PlainFeatureData, error) {
return GetTargetFeatureConfig(cliCtx, featureManagerTypes.TronDynamicCheckpoint)
}

func GetFinalizedEthOpen(cliCtx cliContext.CLIContext) bool {
feature, err := GetTargetFeatureConfig(cliCtx, featureManagerTypes.FinalizedEth)
if err != nil {
Expand Down
18 changes: 17 additions & 1 deletion checkpoint/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,29 @@ func handleMsgCheckpointNoAck(ctx sdk.Context, msg types.MsgCheckpointNoAck, k K
// Get buffer time from params
bufferTime := k.GetParams(ctx).CheckpointBufferTime

var checkpointPollInterval time.Duration
if k.GetParams(ctx).CheckpointPollInterval > 0 {
checkpointPollInterval = k.GetParams(ctx).CheckpointPollInterval
} else {
checkpointPollInterval = helper.GetConfig().CheckpointerPollInterval
}

var checkpointTimeout time.Duration
tronDynamicFeature := util.GetFeatureConfig().GetFeature(ctx, featuremanagerTypes.TronDynamicCheckpoint)
if tronDynamicFeature.IsOpen {
tronMaxLength := tronDynamicFeature.IntConf["maxLength"]
checkpointTimeout, _ = helper.CalcCheckpointTimeout(tronMaxLength, checkpointPollInterval)
} else {
checkpointTimeout = checkpointPollInterval
}

// Fetch last checkpoint from store
// TODO figure out how to handle this error
lastCheckpoint, _ := k.GetLastCheckpoint(ctx, hmTypes.RootChainTypeStake)
lastCheckpointTime := time.Unix(int64(lastCheckpoint.TimeStamp), 0)

// If last checkpoint is not present or last checkpoint happens before checkpoint buffer time -- thrown an error
if lastCheckpointTime.After(currentTime) || (currentTime.Sub(lastCheckpointTime) < bufferTime) {
if lastCheckpointTime.After(currentTime) || (currentTime.Sub(lastCheckpointTime) < checkpointTimeout) {
logger.Debug("Invalid No ACK -- Waiting for last checkpoint ACK")
return common.ErrInvalidNoACK(k.Codespace()).Result()
}
Expand Down
73 changes: 70 additions & 3 deletions checkpoint/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/maticnetwork/heimdall/checkpoint"
chSim "github.com/maticnetwork/heimdall/checkpoint/simulation"

featuremanagerTypes "github.com/maticnetwork/heimdall/featuremanager/types"
"github.com/maticnetwork/heimdall/helper/mocks"
hmTypes "github.com/maticnetwork/heimdall/types"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -332,7 +333,6 @@ func (suite *HandlerTestSuite) TestHandleMsgCheckpointNoAck() {
start := uint64(0)
maxSize := uint64(256)
params := keeper.GetParams(ctx)
checkpointBufferTime := params.CheckpointBufferTime

dividendAccount := hmTypes.DividendAccount{
User: hmTypes.HexToHeimdallAddress("123"),
Expand All @@ -359,8 +359,75 @@ func (suite *HandlerTestSuite) TestHandleMsgCheckpointNoAck() {
require.True(t, got.IsOK(), "expected send-NoAck to be ok, got %v", got)

// set time lastCheckpoint timestamp + checkpointBufferTime
newTime := lastCheckpoint.TimeStamp + uint64(checkpointBufferTime)
suite.ctx = ctx.WithBlockTime(time.Unix(0, int64(newTime)))
checkpointTimeout := 10 * time.Minute
newTime := time.Unix(int64(lastCheckpoint.TimeStamp), int64(checkpointTimeout))
suite.ctx = ctx.WithBlockTime(newTime)
result := suite.SendNoAck()
require.True(t, result.IsOK(), "expected send-NoAck to be ok, got %v", got)
ackCount := keeper.GetACKCount(ctx, hmTypes.RootChainTypeStake)
require.Equal(t, uint64(0), uint64(ackCount), "Should not update state")
}

func (suite *HandlerTestSuite) TestHandleMsgCheckpointNoAckWithTronDynamicOpen() {
t, app, ctx := suite.T(), suite.app, suite.ctx
keeper := app.CheckpointKeeper
stakingKeeper := app.StakingKeeper
topupKeeper := app.TopupKeeper
featureKeeper := app.FeatureKeeper
start := uint64(0)
maxSize := uint64(256)
params := keeper.GetParams(ctx)

open := true

featureParams := featuremanagerTypes.FeatureParams{
FeatureParamMap: map[string]featuremanagerTypes.FeatureData{
featuremanagerTypes.DynamicCheckpoint: {IsOpen: &open,
IntConf: map[string]int{
"eth": 1,
"maxLength": 1024,
}},
featuremanagerTypes.FinalizedEth: {IsOpen: &open},
},
}
featureData := featuremanagerTypes.FeatureData{
IsOpen: &open,
IntConf: map[string]int{
"maxLength": 1024,
},
}
featureParams.FeatureParamMap[featuremanagerTypes.TronDynamicCheckpoint] = featureData

featureKeeper.SetFeatureParams(ctx, featureParams)

dividendAccount := hmTypes.DividendAccount{
User: hmTypes.HexToHeimdallAddress("123"),
FeeAmount: big.NewInt(0).String(),
}
topupKeeper.AddDividendAccount(ctx, dividendAccount)

// check valid checkpoint
// generate proposer for validator set
chSim.LoadValidatorSet(2, t, stakingKeeper, ctx, false, 10)
stakingKeeper.IncrementAccum(ctx, 1)

lastCheckpoint, err := keeper.GetLastCheckpoint(ctx, hmTypes.RootChainTypeStake)
if err == nil {
start = start + lastCheckpoint.EndBlock + 1
}

header, err := chSim.GenRandCheckpoint(start, maxSize, params.MaxCheckpointLength)

// add current proposer to header
header.Proposer = stakingKeeper.GetValidatorSet(ctx).Proposer.Signer

got := suite.SendCheckpoint(header)
require.True(t, got.IsOK(), "expected send-NoAck to be ok, got %v", got)

// set time lastCheckpoint timestamp + checkpointBufferTime
checkpointTimeout := 40 * time.Minute
newTime := time.Unix(int64(lastCheckpoint.TimeStamp), int64(checkpointTimeout))
suite.ctx = ctx.WithBlockTime(newTime)
result := suite.SendNoAck()
require.True(t, result.IsOK(), "expected send-NoAck to be ok, got %v", got)
ackCount := keeper.GetACKCount(ctx, hmTypes.RootChainTypeStake)
Expand Down
3 changes: 1 addition & 2 deletions checkpoint/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ func createTestApp(isCheckTx bool) (*app.HeimdallApp, sdk.Context, context.CLICo
cliCtx := context.NewCLIContext().WithCodec(app.Codec())

helper.SetTestConfig(helper.GetDefaultHeimdallConfig())

params := types.NewParams(5*time.Second, 256, 1024, 10000, 30*time.Minute)
params := types.NewParams(5*time.Second, 256, 1024, 10000, 10*time.Minute)

Checkpoints := make([]hmTypes.Checkpoint, 0)

Expand Down
9 changes: 5 additions & 4 deletions featuremanager/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ const (
)

const (
SupportMapMarshaling = "SupportMapMarshaling"
DynamicCheckpoint = "DynamicCheckpoint"
FinalizedEth = "FinalizedEth"
NoAckValidatorCheck = "NoAckValidatorCheck"
SupportMapMarshaling = "SupportMapMarshaling"
DynamicCheckpoint = "DynamicCheckpoint"
FinalizedEth = "FinalizedEth"
NoAckValidatorCheck = "NoAckValidatorCheck"
TronDynamicCheckpoint = "TronDynamicCheckpoint"
)
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ require (
github.com/prometheus/procfs v0.9.0 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rjeczalik/notify v0.9.2 // indirect
github.com/rjeczalik/notify v0.9.3 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1554,8 +1554,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY=
github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
Expand Down
4 changes: 3 additions & 1 deletion helper/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,8 @@ func (c *ContractCaller) GetStartListenBlock(rootChainType string) uint64 {
return GetConfig().TronStartListenBlock
} else if rootChainType == hmTypes.RootChainTypeEth {
return GetConfig().EthStartListenBlock
} else if rootChainType == hmTypes.RootChainTypeBsc {
return GetConfig().BscStartListenBlock
} else {
return 0
}
Expand All @@ -1104,7 +1106,7 @@ func (c *ContractCaller) GetTronHeaderInfo(headerID uint64, contractAddress stri
}

// Call
data, err := c.TronChainRPC.TriggerConstantContract(contractAddress, btsPack)
data, err := c.TronChainRPC.TriggerConstantContractWithRetry(contractAddress, btsPack)
if err != nil {
return root, 0, 0, 0, types.HeimdallAddress{}, err
}
Expand Down
2 changes: 2 additions & 0 deletions helper/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ type Configuration struct {

TronStartListenBlock uint64 `mapstructure:"tron_start_listen_block"` // tron chain start listen block on bridge
EthStartListenBlock uint64 `mapstructure:"eth_start_listen_block"` // eth chain start listen block on bridge
BscStartListenBlock uint64 `mapstructure:"bsc_start_listen_block"`

EthUnconfirmedTxsBusyLimit int `mapstructure:"eth_unconfirmed_txs_busy_limit"` // the busy limit of unconfirmed txs on heimdall for eth
BscUnconfirmedTxsBusyLimit int `mapstructure:"bsc_unconfirmed_txs_busy_limit"` // the busy limit of unconfirmed txs on heimdall for bsc
Expand Down Expand Up @@ -317,6 +318,7 @@ func GetDefaultHeimdallConfig() Configuration {
TronGridApiKey: DefaultTronGridApiKey,
TronStartListenBlock: DefaultStartListenBlock,
EthStartListenBlock: DefaultStartListenBlock,
BscStartListenBlock: DefaultStartListenBlock,

EthUnconfirmedTxsBusyLimit: DefaultEthBusyLimitTxs,
BscUnconfirmedTxsBusyLimit: DefaultBscBusyLimitTxs,
Expand Down
14 changes: 14 additions & 0 deletions helper/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os"
"path"
"sort"
"time"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
Expand Down Expand Up @@ -51,6 +52,8 @@ var ZeroAddress = common.Address{}
// ZeroPubKey represents empty pub key
var ZeroPubKey = hmTypes.PubKey{}

const BttcBlockInterval = 2 * time.Second

// GetFromAddress get from address
func GetFromAddress(cliCtx context.CLIContext) types.HeimdallAddress {
fromAddress := cliCtx.GetFromAddress()
Expand Down Expand Up @@ -888,3 +891,14 @@ func Hash(s []byte) ([]byte, error) {
bs := h.Sum(nil)
return bs, nil
}

func CalcCheckpointTimeout(tronMaxLength int, pollTime time.Duration) (time.Duration, error) {
if pollTime <= 0 {
return 0, errors.New("pollTime must be greater than 0")
}

timeForBttcBlocks := time.Duration(tronMaxLength) * BttcBlockInterval

checkpointTimeout := ((timeForBttcBlocks + pollTime - 1) / pollTime) * pollTime
return checkpointTimeout, nil
}
8 changes: 8 additions & 0 deletions helper/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/hex"
"math/big"
"testing"
"time"

"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -63,3 +64,10 @@ func TestGetPowerFromAmount(t *testing.T) {
require.Equal(t, p.String(), v, "Power must match")
}
}

func TestCalcCheckpointTimeout(t *testing.T) {
tronMaxLength := 1024
pollTime := 10 * time.Minute
checkpointTimeout, _ := CalcCheckpointTimeout(tronMaxLength, pollTime)
require.Equal(t, 40*time.Minute, checkpointTimeout, "checkpointTimeout should match")
}
27 changes: 23 additions & 4 deletions tron/tronclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"math/big"
"os"
"strings"
"time"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -36,9 +37,7 @@ func NewClient(url string) *Client {
}
}

//
// private abi methods
//
func getABI(data string) (abi.ABI, error) {
return abi.JSON(strings.NewReader(data))
}
Expand Down Expand Up @@ -81,6 +80,26 @@ func (tc *Client) TriggerConstantContract(contractAddress string, data []byte) (
return response.ConstantResult[0], nil
}

func (tc *Client) TriggerConstantContractWithRetry(contractAddress string, data []byte) ([]byte, error) {
const maxRetries = 3

var response []byte
var err error

for attempt := 0; attempt < maxRetries; attempt++ {
response, err = tc.TriggerConstantContract(contractAddress, data)

if err == nil && response != nil {
break
}
if attempt < maxRetries-1 {
delay := attempt
time.Sleep(time.Duration(delay) * time.Second)
}

}
return response, err
}
func (tc *Client) GetNowBlock(ctx context.Context) (int64, error) {
block, err := tc.client.GetNowBlock2(ctx, &pb.EmptyMessage{})
if err != nil {
Expand All @@ -100,7 +119,7 @@ func (tc *Client) CurrentHeaderBlock(contractAddress string, childBlockInterval
}

// Call
data, err := tc.TriggerConstantContract(contractAddress, btsPack)
data, err := tc.TriggerConstantContractWithRetry(contractAddress, btsPack)
if err != nil {
return 0, err
}
Expand All @@ -125,7 +144,7 @@ func (tc *Client) GetLastChildBlock(contractAddress string) (uint64, error) {
if err != nil {
return 0, err
}
data, err := tc.TriggerConstantContract(contractAddress, btsPack)
data, err := tc.TriggerConstantContractWithRetry(contractAddress, btsPack)
if err != nil {
return 0, err
}
Expand Down
Loading