Skip to content

Commit

Permalink
cleanup and add some comments
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed Oct 22, 2024
1 parent ce386fb commit 7b0b3d6
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 37 deletions.
65 changes: 41 additions & 24 deletions challenger/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Challenger

The Challenger is responsible for
The Challenger is responsible for

1. verifying that the `MsgInitiateTokenDeposit` event is properly relayed to `MsgFinalizeTokenDeposit`.
2. checking whether `MsgInitiateTokenDeposit` was relayed on time.
3. verifying that the `Oracle` data is properly relayed to `MsgUpdateOracle`.
Expand Down Expand Up @@ -44,9 +45,10 @@ To configure the Challenger, fill in the values in the `~/.opinit/challenger.jso
```

### Start height config examples

If the latest height stored in the db is not 0, start height config is ignored.

```
```shell
Output tx 1
- L1BlockNumber: 10
- L2BlockNumber: 100
Expand All @@ -71,62 +73,75 @@ FinalizedTokenDeposit tx 2
```

#### Config 1

```json
{
l2_start_height: 150,
}
```

When Child's last l1 Sequence is `2`,

- L1 starts from the height 10 + 1 = 11
- L2 starts from the height 100 + 1 = 101


## Handler rules for the components of the Challenger
For registered events or tx handlers, work processed in a block is atomically saved as `pending events`. Therefore, if `pending events` with the `ChallengeEvent` interface cannot be processed due to an interrupt or error, it is guaranteed to be read from the DB and processed. When an event matching the pending event comes in and is processed, or when the block time exceeds the event's timeout, a `Challenge` is created and stored in the DB.
#### The challenger can check the generated `Challenges` and decide what action to take.

For registered events or tx handlers, work processed in a block is atomically saved as `pending events`. Therefore, if `pending events` with the `ChallengeEvent` interface cannot be processed due to an interrupt or error, it is guaranteed to be read from the DB and processed. When an event matching the pending event comes in and is processed, or when the block time exceeds the event's timeout, a `Challenge` is created and stored in the DB.

### The challenger can check the generated `Challenges` and decide what action to take

## Deposit

When the `initiate_token_deposit` event is detected in l1, saves it as a `Deposit` challenge event and check if it is the same as the `MsgFinalizeTokenDeposit` for the same sequence.

```go
// Deposit is the challenge event for the deposit
type Deposit struct {
EventType string `json:"event_type"`
Sequence uint64 `json:"sequence"`
L1BlockHeight int64 `json:"l1_block_height"`
From string `json:"from"`
To string `json:"to"`
L1Denom string `json:"l1_denom"`
Amount string `json:"amount"`
Time time.Time `json:"time"`
Timeout bool `json:"timeout"`
EventType string `json:"event_type"`
Sequence uint64 `json:"sequence"`
L1BlockHeight int64 `json:"l1_block_height"`
From string `json:"from"`
To string `json:"to"`
L1Denom string `json:"l1_denom"`
Amount string `json:"amount"`
Time time.Time `json:"time"`
Timeout bool `json:"timeout"`
}
```

## Output

When the `propose_output` event is detected in l1, saves it as a `Output` challenge event, replays up to l2 block number and check if `OutputRoot` is the same as submitted.

```go
// Output is the challenge event for the output
type Output struct {
EventType string `json:"event_type"`
L2BlockNumber int64 `json:"l2_block_number"`
OutputIndex uint64 `json:"output_index"`
OutputRoot []byte `json:"output_root"`
Time time.Time `json:"time"`
Timeout bool `json:"timeout"`
EventType string `json:"event_type"`
L2BlockNumber int64 `json:"l2_block_number"`
OutputIndex uint64 `json:"output_index"`
OutputRoot []byte `json:"output_root"`
Time time.Time `json:"time"`
Timeout bool `json:"timeout"`
}
```

## Oracle

If `oracle_enable` is turned on in bridge config, saves bytes of the 0th Tx as a `Oracle` challenge event and check if it is the same data in the `MsgUpdateOracle` for the l1 height.

## Batch
Batch data is not verified by the challenger bot.
#### TODO
* Challenger runs a L2 node it in rollup sync challenge mode in CometBFT to check whether the submitted batch is replayed properly.

Batch data is not verified by the challenger bot.

### TODO

- Challenger runs a L2 node it in rollup sync challenge mode in CometBFT to check whether the submitted batch is replayed properly.

## Query

### Status

```bash
curl localhost:3001/status
```
Expand Down Expand Up @@ -161,6 +176,7 @@ curl localhost:3001/status
```

### Challenges

```bash
curl localhost:3001/challenges/{page}
```
Expand All @@ -180,6 +196,7 @@ curl localhost:3001/challenges/{page}
```

### Pending events

```bash
curl localhost:3001/pending_events/host
```
Expand Down Expand Up @@ -211,4 +228,4 @@ curl localhost:3001/pending_events/child
"timeout": false
}
]
```
```
4 changes: 4 additions & 0 deletions challenger/challenger.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ func (c *Challenger) Initialize(ctx context.Context) error {
if initialBlockTime.Before(childInitialBlockTime) {
initialBlockTime = childInitialBlockTime
}

// only called when `ResetHeight` is executed.`
if !initialBlockTime.IsZero() {
// The db state is reset to a specific height, so we also
// need to delete future challenges which are not applicable anymore.
err := c.DeleteFutureChallenges(initialBlockTime)
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions challenger/child/child.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func (ch *Child) Initialize(ctx context.Context, processedHeight int64, startOut
}

var blockTime time.Time

// only called when `ResetHeight` was executed.
if ch.Node().HeightInitialized() {
blockTime, err = ch.Node().QueryBlockTime(ctx, ch.Node().GetHeight())
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions challenger/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func (h *Host) Initialize(ctx context.Context, processedHeight int64, child chil
}

var blockTime time.Time

// only called when `ResetHeight` was executed.
if h.Node().HeightInitialized() {
blockTime, err = h.Node().QueryBlockTime(ctx, h.Node().GetHeight())
if err != nil {
Expand Down
29 changes: 16 additions & 13 deletions challenger/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,36 @@ var (
StatusKey = []byte("status")
)

func PrefixedEventType(eventType EventType) []byte {
func prefixedEventType(eventType EventType) []byte {
return append([]byte{byte(eventType)}, dbtypes.Splitter)
}

func PrefixedEventTypeId(eventType EventType, id uint64) []byte {
return append(PrefixedEventType(eventType), dbtypes.FromUint64Key(id)...)
func prefixedEventTypeId(eventType EventType, id uint64) []byte {
return append(prefixedEventType(eventType), dbtypes.FromUint64Key(id)...)
}

func PrefixedPendingEvent(id ChallengeId) []byte {
return append(append(PendingEventKey, dbtypes.Splitter),
PrefixedEventTypeId(id.Type, id.Id)...)
prefixedEventTypeId(id.Type, id.Id)...)
}

func PrefixedPendingChallenge(id ChallengeId) []byte {
return append(append(PendingChallengeKey, dbtypes.Splitter),
PrefixedEventTypeId(id.Type, id.Id)...)
prefixedEventTypeId(id.Type, id.Id)...)
}

func PrefixedTimeEvent(eventTime time.Time) []byte {
func prefixedTimeEvent(eventTime time.Time) []byte {
return append(dbtypes.FromUint64Key(types.MustInt64ToUint64(eventTime.UnixNano())), dbtypes.Splitter)
}

func PrefixedChallengeEventTime(eventTime time.Time) []byte {
func prefixedChallengeEventTime(eventTime time.Time) []byte {
return append(append(ChallengeKey, dbtypes.Splitter),
PrefixedTimeEvent(eventTime)...)
prefixedTimeEvent(eventTime)...)
}

func PrefixedChallenge(eventTime time.Time, id ChallengeId) []byte {
return append(PrefixedChallengeEventTime(eventTime),
PrefixedEventTypeId(id.Type, id.Id)...)
return append(prefixedChallengeEventTime(eventTime),
prefixedEventTypeId(id.Type, id.Id)...)
}

func ParsePendingEvent(key []byte) (ChallengeId, error) {
Expand All @@ -63,8 +63,11 @@ func ParseChallenge(key []byte) (time.Time, ChallengeId, error) {
return time.Time{}, ChallengeId{}, errors.New("invalid key bytes")
}

timeBz := key[len(key)-19 : len(key)-11]
typeBz := key[len(key)-10 : len(key)-9]
idBz := key[len(key)-8:]
cursor := 0
timeBz := key[cursor : cursor+8]
cursor += 8 + 1 // u64 + splitter
typeBz := key[cursor : cursor+1]
cursor += 1 + 1 // u8 + splitter
idBz := key[cursor:]
return time.Unix(0, types.MustUint64ToInt64(dbtypes.ToUint64Key(timeBz))), ChallengeId{Type: EventType(typeBz[0]), Id: dbtypes.ToUint64Key(idBz)}, nil
}

0 comments on commit 7b0b3d6

Please sign in to comment.