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
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ jobs:
run: |
make chain
make contracts
# epoch length is fixed in lorentz HF.
# epoch is 200, 400, 500, 1000
# must wait for 1000 block (1.5sec * 1000)
sleep 1500
# must wait for 400 block (1.5sec * 400)
sleep 600
make relayer
make test
- name: integration-test
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
![CI](https://github.com/datachainlab/ibc-parlia-relay/workflows/CI/badge.svg?branch=main)

## Supported Versions
- [yui-relayer v0.5.3](https://github.com/hyperledger-labs/yui-relayer/releases/tag/v0.5.3)
- [ethereum-ibc-relay-chain v0.3.4](https://github.com/datachainlab/ethereum-ibc-relay-chain/releases/tag/v0.3.4)
- [yui-relayer v0.5.11](https://github.com/hyperledger-labs/yui-relayer/releases/tag/v0.5.11)
- [ethereum-ibc-relay-chain v0.3.16](https://github.com/datachainlab/ethereum-ibc-relay-chain/releases/tag/v0.3.6)

## Setup Relayer

Expand All @@ -29,14 +29,6 @@ func main() {
}
```

## Change blocks per epoch

* You can change blocks per epoch by build arguments.
* This is only for local net.
```
go build -tags dev -ldflags="-X github.com/datachainlab/ibc-parlia-relay/module/constant.blocksPerEpoch=20" -o testrly .
```

## Development

Generate proto buf with protobuf definition of [parlia-elc](https://github.com/datachainlab/parlia-elc).
Expand All @@ -48,3 +40,12 @@ cd ibc-parlia-relay
make proto-import
make proto-gen
```

## About ForkSpec

1. Set HF height as soon as possible
As soon as the HF height is determined, please modify the timestamp in the ForkSpec to the height as soon as possible.
HF height is calculated from timestamp, but the further away from the HF, the longer it takes to calculate.

2. Limitation of the CreateClient
When the latest HF height is not set it is impossible to create client if the latest finalize header is after latest HF timestamp
4 changes: 2 additions & 2 deletions e2e/chains/bsc/Dockerfile.bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ FROM ghcr.io/foundry-rs/foundry:nightly-462b2ac6c038dc24b8f38b0c59b664d0740604c2
RUN apk add --d --no-cache ca-certificates npm nodejs bash alpine-sdk expect jq curl bash python3
RUN curl -sSL https://install.python-poetry.org | python3 -

RUN git clone https://github.com/bnb-chain/bsc-genesis-contract -b v1.2.4 /root/genesis \
&& cd /root/genesis && npm ci
RUN git clone https://github.com/bnb-chain/bsc-genesis-contract -b develop /root/genesis \
&& cd /root/genesis && git checkout 44ebc6c17a00bd24db3240141a78091528dcebbb && npm ci

RUN cd /root/genesis && /root/.local/bin/poetry install
RUN cd /root/genesis && forge install --no-git --no-commit foundry-rs/forge-std@v1.7.3
Expand Down
2 changes: 1 addition & 1 deletion e2e/chains/bsc/docker-compose.bsc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ services:
dockerfile: Dockerfile.bsc
args:
GIT_SOURCE: https://github.com/bnb-chain/bsc
GIT_CHECKOUT_BRANCH: develop
GIT_CHECKOUT_BRANCH: v1.5.9
image: bsc-geth:docker-local
436 changes: 52 additions & 384 deletions e2e/chains/bsc/genesis/contracts/BSCValidatorSet.sol

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions e2e/chains/bsc/genesis/genesis-template.template
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
},
"lorentz": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
}
},
"parlia": {
Expand Down
2 changes: 1 addition & 1 deletion e2e/chains/bsc/genesis/scripts/init_holders.template
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const web3 = require("web3")

const addresses = "{{INIT_HOLDER_ADDRESSES}}"
const balance = web3.utils.toBN("{{INIT_HOLDER_BALANCE}}").toString("hex")
const balance = BigInt("{{INIT_HOLDER_BALANCE}}").toString(16)
const init_holders = addresses.split(",").map(address => ({ address, balance }));

exports = module.exports = init_holders
3 changes: 0 additions & 3 deletions module/constant/production.go

This file was deleted.

9 changes: 0 additions & 9 deletions module/facade.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ import (
)

// Facade for tool modules

func GetPreviousEpoch(v uint64) uint64 {
return getPreviousEpoch(v)
}

func GetCurrentEpoch(v uint64) uint64 {
return getCurrentEpoch(v)
}

func QueryFinalizedHeader(ctx context.Context, fn getHeaderFn, height uint64, limitHeight uint64) ([]*ETHHeader, error) {
return queryFinalizedHeader(ctx, fn, height, limitHeight)
}
Expand Down
215 changes: 212 additions & 3 deletions module/fork_spec.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package module

import (
"context"
"fmt"
"github.com/hyperledger-labs/yui-relayer/log"
"math"
"os"
"strconv"
)

type Network string

const (
Expand All @@ -8,29 +17,229 @@ const (
Mainnet Network = "mainnet"
)

var localLorentzHF isForkSpec_HeightOrTimestamp = &ForkSpec_Height{Height: 1}

func init() {
localLorentzHFTimestamp := os.Getenv("LOCAL_LORENTZ_HF_TIMESTAMP")
if localLorentzHFTimestamp != "" {
result, err := strconv.Atoi(localLorentzHFTimestamp)
if err != nil {
panic(err)
}
localLorentzHF = &ForkSpec_Timestamp{Timestamp: uint64(result)}
}
}

func GetForkParameters(network Network) []*ForkSpec {
switch network {
case Localnet:
return []*ForkSpec{
// Pascal HF
{
HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 0},
// Must Set Milli timestamp
HeightOrTimestamp: &ForkSpec_Height{Height: 0},
AdditionalHeaderItemCount: 1,
EpochLength: 200,
MaxTurnLength: 9,
},
// Lorentz HF
{
// Must Set Milli timestamp
HeightOrTimestamp: localLorentzHF,
AdditionalHeaderItemCount: 1,
EpochLength: 500,
MaxTurnLength: 64,
},
}
case Testnet:
return []*ForkSpec{
{
HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 0},
// https://forum.bnbchain.org/t/bnb-chain-upgrades-testnet/934
HeightOrTimestamp: &ForkSpec_Height{Height: 48576786},
AdditionalHeaderItemCount: 1,
EpochLength: 200,
MaxTurnLength: 9,
},
{
HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 1744097580 * 1000},
AdditionalHeaderItemCount: 1,
EpochLength: 500,
MaxTurnLength: 64,
},
}
case Mainnet:
return []*ForkSpec{
{
HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: 0},
// https://bscscan.com/block/47618307
// https://github.com/bnb-chain/bsc/releases/tag/v1.5.7
HeightOrTimestamp: &ForkSpec_Height{Height: 47618307},
AdditionalHeaderItemCount: 1,
EpochLength: 200,
MaxTurnLength: 9,
},
{
HeightOrTimestamp: &ForkSpec_Timestamp{Timestamp: math.MaxUint64},
AdditionalHeaderItemCount: 1,
EpochLength: 500,
MaxTurnLength: 64,
},
}
}
return nil
}

type BoundaryEpochs struct {
PreviousForkSpec ForkSpec
CurrentForkSpec ForkSpec
BoundaryHeight uint64
PrevLast uint64
CurrentFirst uint64
Intermediates []uint64
}

type BoundaryHeight struct {
Height uint64
CurrentForkSpec ForkSpec
}

func (b BoundaryHeight) GetBoundaryEpochs(prevForkSpec ForkSpec) (*BoundaryEpochs, error) {
boundaryHeight := b.Height
prevLast := boundaryHeight - (boundaryHeight % prevForkSpec.EpochLength)
index := uint64(0)
currentFirst := uint64(0)
for {
candidate := boundaryHeight + index
if candidate%b.CurrentForkSpec.EpochLength == 0 {
currentFirst = candidate
break
}
index++
}
intermediates := make([]uint64, 0)
// starts 0, 200, 400...epoch_length
if prevLast == 0 {
const defaultEpochLength = 200
for mid := prevLast + defaultEpochLength; mid < prevForkSpec.EpochLength; mid += defaultEpochLength {
intermediates = append(intermediates, mid)
}
}
for mid := prevLast + prevForkSpec.EpochLength; mid < currentFirst; mid += prevForkSpec.EpochLength {
intermediates = append(intermediates, mid)
}

return &BoundaryEpochs{
PreviousForkSpec: prevForkSpec,
CurrentForkSpec: b.CurrentForkSpec,
BoundaryHeight: boundaryHeight,
PrevLast: prevLast,
CurrentFirst: currentFirst,
Intermediates: intermediates,
}, nil
}

func (be BoundaryEpochs) CurrentEpochBlockNumber(number uint64) uint64 {
if number >= be.CurrentFirst {
return number - (number % be.CurrentForkSpec.EpochLength)
}

if len(be.Intermediates) > 0 {
for i := len(be.Intermediates) - 1; i >= 0; i-- {
if number >= be.Intermediates[i] {
return be.Intermediates[i]
}
}
}
return number - (number % be.PreviousForkSpec.EpochLength)
}

func (be BoundaryEpochs) PreviousEpochBlockNumber(currentEpochBlockNumber uint64) uint64 {
if currentEpochBlockNumber == 0 {
return 0
}
if currentEpochBlockNumber <= be.PrevLast {
return currentEpochBlockNumber - be.PreviousForkSpec.EpochLength
}

for i, mid := range be.Intermediates {
if currentEpochBlockNumber == mid {
if i == 0 {
return be.PrevLast
}
return be.Intermediates[i-1]
}
}

if currentEpochBlockNumber == be.CurrentFirst {
if len(be.Intermediates) == 0 {
return be.PrevLast
}
return be.Intermediates[len(be.Intermediates)-1]
}

return currentEpochBlockNumber - be.CurrentForkSpec.EpochLength
}

func FindTargetForkSpec(forkSpecs []*ForkSpec, height uint64, timestamp uint64) (*ForkSpec, *ForkSpec, error) {
reversed := make([]*ForkSpec, len(forkSpecs))
for i, spec := range forkSpecs {
reversed[len(forkSpecs)-i-1] = spec
}

getPrev := func(current *ForkSpec, i int) *ForkSpec {
if i == len(reversed)-1 {
return current
}
return reversed[i+1]
}

for i, spec := range reversed {
if x, ok := spec.GetHeightOrTimestamp().(*ForkSpec_Height); ok {
if x.Height <= height {
return spec, getPrev(spec, i), nil
}
} else {
if spec.GetTimestamp() <= timestamp {
return spec, getPrev(spec, i), nil
}
}
}
return nil, nil, fmt.Errorf("no fork spec found height=%d, timestmp=%d", height, timestamp)
}

var boundaryHeightCache = make(map[uint64]uint64)

func GetBoundaryHeight(headerFn getHeaderFn, currentHeight uint64, currentForkSpec ForkSpec) (*BoundaryHeight, error) {
logger := log.GetLogger()
boundaryHeight := uint64(0)
if condition, ok := currentForkSpec.GetHeightOrTimestamp().(*ForkSpec_Height); ok {
boundaryHeight = condition.Height
} else {
ts := currentForkSpec.GetTimestamp()
if v, ok := boundaryHeightCache[ts]; ok {
boundaryHeight = v
} else {
logger.Debug("seek fork height", "currentHeight", currentHeight, "ts", ts)
for i := int64(currentHeight); i >= 0; i-- {
Copy link
Member

Choose a reason for hiding this comment

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

Optional optimization: Consider estimating heights near hardfork points using ForkSpec's block generation time to reduce header query overhead. This isn't a required fix but could improve performance for post-hardfork requests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will be supported after the next version release. There is a grace period until the next Maxwell HF.

h, err := headerFn(context.Background(), uint64(i))
if err != nil {
return nil, err
}
if MilliTimestamp(h) == ts {
boundaryHeight = h.Number.Uint64()
logger.Debug("seek fork height found", "currentHeight", currentHeight, "ts", ts, "boundaryHeight", boundaryHeight)
boundaryHeightCache[ts] = boundaryHeight
break
} else if MilliTimestamp(h) < ts {
boundaryHeight = h.Number.Uint64() + 1
logger.Debug("seek fork height found", "currentHeight", currentHeight, "ts", ts, "boundaryHeight", boundaryHeight)
boundaryHeightCache[ts] = boundaryHeight
break
}
}
}
}
return &BoundaryHeight{
Height: boundaryHeight,
CurrentForkSpec: currentForkSpec,
}, nil
}
Loading