Skip to content

Commit 6695578

Browse files
authored
[SEQ-241] Adding new batch provider for abritrum with scaffolding for block fetching (#32)
* Adding new batch provider for abritrum with scaffolding for block fetching * Using const
1 parent 2989b2a commit 6695578

File tree

8 files changed

+272
-15
lines changed

8 files changed

+272
-15
lines changed

op-translator/internal/config/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Config struct {
3838
BatcherPrivateKey string `koanf:"batcher_private_key"`
3939
LogLevel string `koanf:"log_level"`
4040
SettlementChainID int64 `koanf:"settlement_chain_id"`
41+
SettlementChainBlockTime int `koanf:"settlement_chain_block_time"`
4142
SettlementStartBlock int `koanf:"settlement_start_block"`
4243
SequencingStartBlock int `koanf:"sequencing_start_block"`
4344
SequencePerSettlementBlock int `koanf:"sequence_per_settlement_block"`
@@ -64,6 +65,7 @@ func setCLIFlags(f *pflag.FlagSet) {
6465
f.Int("sequence_per_settlement_block", 0, "Number of sequencing blocks per settlement block")
6566
f.String("batcher_private_key", "", "Batcher private key")
6667
f.Int("settlement_chain_id", 1, "Settlement chain id")
68+
f.Int("settlement_chain_block_time", 1, "Settlement chain block time")
6769
}
6870

6971
// hydrateFromConfMap sets the Config values from the koanf conf map
@@ -85,6 +87,7 @@ func hydrateFromConfMap(config *Config) {
8587
config.SequencePerSettlementBlock = k.Int("sequence_per_settlement_block")
8688
config.BatcherPrivateKey = k.String("batcher_private_key")
8789
config.SettlementChainID = k.Int64("settlement_chain_id")
90+
config.SettlementChainBlockTime = k.Int("settlement_chain_block_time")
8891
}
8992

9093
func Init() *Config {
@@ -195,5 +198,9 @@ func ValidateConfigValues(config *Config) (result error) {
195198
result = multierror.Append(result, fmt.Errorf("settlementChainID must be a positive number: %d", config.SettlementChainID))
196199
}
197200

201+
if config.SettlementChainBlockTime <= 0 {
202+
result = multierror.Append(result, fmt.Errorf("settlementChainBlockTime must be a positive number: %d", config.SettlementChainBlockTime))
203+
}
204+
198205
return result
199206
}

op-translator/internal/config/config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func validConfig() config.Config {
2929
SequencePerSettlementBlock: 2,
3030
BatcherPrivateKey: "fcd8aa9464a41a850d5bbc36cd6c4b6377e308a37869add1c2cf466b8d65826d",
3131
SettlementChainID: 84532,
32+
SettlementChainBlockTime: 2,
3233
}
3334
}
3435

op-translator/internal/utils/utils.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"strings"
77
)
88

9+
const MillisecondsPerSecond = 1000
10+
911
func HexToInt(hexStr string) (int, error) {
1012
if !strings.HasPrefix(hexStr, "0x") {
1113
return 0, errors.New("invalid hex string, must start with 0x")
@@ -30,3 +32,7 @@ func HexToUInt64(hexStr string) (uint64, error) {
3032
func IntToHex(num int) string {
3133
return "0x" + strconv.FormatInt(int64(num), 16)
3234
}
35+
36+
func SecondsToMilliseconds(seconds int) int {
37+
return seconds * MillisecondsPerSecond
38+
}

op-translator/internal/utils/utils_test.go

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"testing"
55

66
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/utils"
7+
"github.com/stretchr/testify/assert"
78
)
89

910
func TestHexToInt(t *testing.T) {
@@ -23,12 +24,11 @@ func TestHexToInt(t *testing.T) {
2324
for _, tt := range tests {
2425
t.Run(tt.name, func(t *testing.T) {
2526
got, err := utils.HexToInt(tt.input)
26-
if (err != nil) != tt.wantErr {
27-
t.Errorf("HexToInt() error = %v, wantErr %v", err, tt.wantErr)
28-
return
29-
}
30-
if got != tt.want {
31-
t.Errorf("HexToInt() = %v, want %v", got, tt.want)
27+
if tt.wantErr {
28+
assert.Error(t, err)
29+
} else {
30+
assert.NoError(t, err)
31+
assert.Equal(t, tt.want, got)
3232
}
3333
})
3434
}
@@ -52,12 +52,11 @@ func TestHexToUInt64(t *testing.T) {
5252
for _, tt := range tests {
5353
t.Run(tt.name, func(t *testing.T) {
5454
got, err := utils.HexToUInt64(tt.input)
55-
if (err != nil) != tt.wantErr {
56-
t.Errorf("HexToUInt64() error = %v, wantErr %v", err, tt.wantErr)
57-
return
58-
}
59-
if got != tt.want {
60-
t.Errorf("HexToUInt64() = %v, want %v", got, tt.want)
55+
if tt.wantErr {
56+
assert.Error(t, err)
57+
} else {
58+
assert.NoError(t, err)
59+
assert.Equal(t, tt.want, got)
6160
}
6261
})
6362
}
@@ -76,9 +75,12 @@ func TestIntToHex(t *testing.T) {
7675

7776
for _, tt := range tests {
7877
t.Run(tt.name, func(t *testing.T) {
79-
if got := utils.IntToHex(tt.input); got != tt.want {
80-
t.Errorf("IntToHex() = %v, want %v", got, tt.want)
81-
}
78+
assert.Equal(t, tt.want, utils.IntToHex(tt.input))
8279
})
8380
}
8481
}
82+
83+
func TestSecondsToMilliseconds(t *testing.T) {
84+
assert.Equal(t, 1000, utils.SecondsToMilliseconds(1))
85+
assert.Equal(t, 2000, utils.SecondsToMilliseconds(2))
86+
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package translator
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"math/big"
8+
9+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/config"
10+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/constants"
11+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/utils"
12+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/pkg/rpc-clients"
13+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/pkg/types"
14+
15+
"github.com/ethereum/go-ethereum/common"
16+
"github.com/ethereum/go-ethereum/common/hexutil"
17+
ethtypes "github.com/ethereum/go-ethereum/core/types"
18+
"github.com/hashicorp/go-multierror"
19+
"github.com/rs/zerolog/log"
20+
)
21+
22+
type MetaBasedBatchProviderArb struct {
23+
MetaBasedChain IRPCClient
24+
SequencingChain IRPCClient
25+
TransactionParser *L3TransactionParser
26+
SequencingBlockFetcher *SequencingBlockFetcher
27+
28+
SettlementStartBlock int
29+
}
30+
31+
func InitMetaBasedBatchProviderArb(cfg *config.Config) *MetaBasedBatchProviderArb {
32+
sequencingChain, err := rpc.Connect(cfg.SequencingChainRPCURL)
33+
if err != nil {
34+
log.Panic().Err(err).Msg("Failed to initialize sequencing chain")
35+
}
36+
37+
metaBasedChain, err := rpc.Connect(cfg.MetaBasedChainRPCURL)
38+
if err != nil {
39+
log.Panic().Err(err).Msg("Failed to initialize metabased chain")
40+
}
41+
42+
return &MetaBasedBatchProviderArb{
43+
MetaBasedChain: metaBasedChain,
44+
SequencingChain: sequencingChain,
45+
TransactionParser: InitL3TransactionParser(cfg),
46+
SequencingBlockFetcher: InitSequencingBlockFetcher(sequencingChain, cfg),
47+
48+
SettlementStartBlock: cfg.SettlementStartBlock,
49+
}
50+
}
51+
52+
func NewMetaBasedBatchProviderArb(
53+
settlementChainClient IRPCClient,
54+
sequencingChainClient IRPCClient,
55+
sequencingContractAddress common.Address,
56+
settlementStartBlock int,
57+
settlementChainBlockTime int,
58+
) *MetaBasedBatchProviderArb {
59+
return &MetaBasedBatchProviderArb{
60+
MetaBasedChain: settlementChainClient,
61+
SequencingChain: sequencingChainClient,
62+
TransactionParser: NewL3TransactionParser(sequencingContractAddress),
63+
SequencingBlockFetcher: NewSequencingBlockFetcher(sequencingChainClient, settlementChainBlockTime),
64+
65+
SettlementStartBlock: settlementStartBlock,
66+
}
67+
}
68+
69+
func (m *MetaBasedBatchProviderArb) Close() {
70+
log.Debug().Msg("Closing Arbitrum MetaBasedBatchProvider")
71+
m.SequencingChain.CloseConnection()
72+
m.MetaBasedChain.CloseConnection()
73+
}
74+
75+
// NOTE [SEQ-144]: THIS ASSUMES THAT THE L3 HAS THE SAME BLOCK TIME AS THE SETTLEMENT L2
76+
func (m *MetaBasedBatchProviderArb) getParentBlockHash(ctx context.Context, blockNumStr string) (string, error) {
77+
log.Debug().Msgf("Getting parent block hash for block number %s", blockNumStr)
78+
blockNum, err := utils.HexToInt(blockNumStr)
79+
if err != nil {
80+
return "", err
81+
}
82+
83+
if blockNum < m.SettlementStartBlock {
84+
return "", errors.New("block number before start block")
85+
}
86+
87+
if blockNum == m.SettlementStartBlock {
88+
return constants.ZeroHash, nil
89+
}
90+
log.Debug().Msgf("Settlement start block: %d", m.SettlementStartBlock)
91+
92+
parentBlockNum := int64(blockNum - m.SettlementStartBlock - 1)
93+
94+
log.Debug().Msgf("Getting block hash for block number %d", parentBlockNum)
95+
previousBlock, err := m.MetaBasedChain.AsEthClient().HeaderByNumber(ctx, big.NewInt(parentBlockNum))
96+
if err != nil {
97+
return "", err
98+
}
99+
log.Debug().Msgf("Previous block: %v", previousBlock)
100+
101+
return previousBlock.Hash().Hex(), nil
102+
}
103+
104+
func (m *MetaBasedBatchProviderArb) FilterReceipts(receipts []*ethtypes.Receipt) (txns []hexutil.Bytes, result error) {
105+
for i, rec := range receipts {
106+
if rec.Status != ethtypes.ReceiptStatusSuccessful {
107+
continue
108+
}
109+
110+
for j, txLog := range rec.Logs {
111+
if m.TransactionParser.IsLogTransactionProcessed(txLog) {
112+
proc, err := m.TransactionParser.ParseTransactionProcessed(txLog)
113+
if err != nil {
114+
result = multierror.Append(result, fmt.Errorf("malformatted l2 receipt log in receipt %d, log %d: %w", i, j, err))
115+
} else {
116+
txns = append(txns, proc.EncodedTxn)
117+
}
118+
}
119+
}
120+
}
121+
return txns, result
122+
}
123+
124+
func (m *MetaBasedBatchProviderArb) GetBatch(ctx context.Context, block types.Block) (*types.Batch, error) {
125+
blockNumber, err := block.GetBlockNumber()
126+
if err != nil {
127+
return nil, err
128+
}
129+
blockHash, err := block.GetBlockHash()
130+
if err != nil {
131+
return nil, err
132+
}
133+
134+
seqBlockNumbers, err := m.SequencingBlockFetcher.GetSequencingBlocks(block)
135+
if err != nil {
136+
return nil, err
137+
}
138+
log.Debug().Msgf("Translating block number %s and hash %s: linked block numbers: %s", blockNumber, blockHash, seqBlockNumbers)
139+
140+
receipts, err := m.SequencingChain.BlocksReceiptsByNumbers(ctx, seqBlockNumbers)
141+
if err != nil {
142+
return nil, err
143+
}
144+
log.Debug().Msgf("Translating block number %s and hash %s: receipts: %v", blockNumber, blockHash, receipts)
145+
146+
txns, err := m.FilterReceipts(receipts)
147+
if err != nil {
148+
return nil, err
149+
}
150+
log.Debug().Msgf("Translating block number %s and hash %s: filtered transactions: %v", blockNumber, blockHash, txns)
151+
152+
parentHash, err := m.getParentBlockHash(ctx, blockNumber)
153+
if err != nil {
154+
return nil, err
155+
}
156+
157+
timestamp, err := block.GetBlockTimestamp()
158+
if err != nil {
159+
return nil, err
160+
}
161+
162+
batch, err := types.NewBatch(parentHash, blockNumber, blockHash, timestamp, txns)
163+
if err != nil {
164+
return nil, err
165+
}
166+
log.Debug().Msgf("Translating block number %s and hash %s: batch: %v", blockNumber, blockHash, batch)
167+
168+
return batch, nil
169+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package translator
2+
3+
import (
4+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/config"
5+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/internal/utils"
6+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/pkg/types"
7+
"github.com/rs/zerolog/log"
8+
)
9+
10+
type SequencingBlockFetcher struct {
11+
SequencingChainClient IRPCClient
12+
13+
SettlementChainBlockTime int
14+
15+
// TODO [SEQ-243]: Add cache to track previous requested sequencing blocks
16+
}
17+
18+
func InitSequencingBlockFetcher(sequencingChainClient IRPCClient, cfg *config.Config) *SequencingBlockFetcher {
19+
return &SequencingBlockFetcher{
20+
SequencingChainClient: sequencingChainClient,
21+
22+
SettlementChainBlockTime: cfg.SettlementChainBlockTime,
23+
}
24+
}
25+
26+
func NewSequencingBlockFetcher(sequencingChainClient IRPCClient, settlementChainBlockTime int) *SequencingBlockFetcher {
27+
return &SequencingBlockFetcher{
28+
SequencingChainClient: sequencingChainClient,
29+
30+
SettlementChainBlockTime: settlementChainBlockTime,
31+
}
32+
}
33+
34+
func (s *SequencingBlockFetcher) GetSequencingBlocks(block types.Block) ([]string, error) {
35+
timestampHex, err := block.GetBlockTimestamp()
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
timeWindowEnd, err := utils.HexToInt(timestampHex)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
timeWindowStart := timeWindowEnd - utils.SecondsToMilliseconds(s.SettlementChainBlockTime)
46+
log.Info().Msgf("Getting sequencing blocks for time window: %d to %d", timeWindowStart, timeWindowEnd)
47+
48+
// TODO [SEQ-242]: Implement getting sequencing blocks by timewindow
49+
return []string{}, nil
50+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package translator
2+
3+
import (
4+
"testing"
5+
6+
"github.com/SyndicateProtocol/metabased-rollup/op-translator/pkg/types"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
var TestBlock = types.Block{
11+
"timestamp": "0x1",
12+
}
13+
14+
func TestGetSequencingBlocks(t *testing.T) {
15+
fetcher := NewSequencingBlockFetcher(nil, 2)
16+
17+
blocks, err := fetcher.GetSequencingBlocks(TestBlock)
18+
assert.NoError(t, err)
19+
// TODO [SEQ-242]: Implement getting sequencing blocks by timewindow
20+
assert.Empty(t, blocks)
21+
}

op-translator/template.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SETTLEMENT_START_BLOCK=<>
1313
SEQUENCING_START_BLOCK=<>
1414
BATCHER_PRIVATE_KEY=<>
1515
SETTLEMENT_CHAIN_ID=84532
16+
SETTLEMENT_CHAIN_BLOCK_TIME=2
1617
BATCH_INBOX_ADDRESS=<>
1718
BATCHER_ADDRESS=<>
1819

0 commit comments

Comments
 (0)