Skip to content

Commit f1514bc

Browse files
ImJeremyHeZaptoss
authored andcommitted
Use espresso streamer in batcher (EspressoSystems#708)
* Use espresso streamer in batcher * Lint * Move helper functions to a new file * Fix msgCount * Fix msg count
1 parent d17e7f8 commit f1514bc

11 files changed

+322
-238
lines changed

arbnode/batch_poster.go

Lines changed: 111 additions & 84 deletions
Large diffs are not rendered by default.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package arbnode
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"math/big"
7+
8+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
9+
"github.com/ethereum/go-ethereum/ethclient"
10+
"github.com/ethereum/go-ethereum/log"
11+
12+
"github.com/offchainlabs/nitro/arbutil"
13+
"github.com/offchainlabs/nitro/espressotee"
14+
"github.com/offchainlabs/nitro/solgen/go/espressogen"
15+
)
16+
17+
// Reads state from external sources and resets the espresso streamer to start producing
18+
// messages from hotshot based on the source of truth on the parent chain
19+
func (b *BatchPoster) resetStreamerToParentChainOrConfigHotshotBlock(messageCount arbutil.MessageIndex, ctx context.Context) {
20+
hotshotBlock := b.fetchHotshotBlockFromLastCheckpoint(ctx)
21+
if hotshotBlock == 0 {
22+
// if there hasn't been a batch posted, or we encountered an error, start reading from the configured hotshot block number.
23+
hotshotBlock = b.config().HotShotBlock
24+
}
25+
b.espressoStreamer.Reset(uint64(messageCount), hotshotBlock)
26+
}
27+
28+
// fetchHotshotBlockFromLastCheckpoint:
29+
// This function uses the sequencer inbox bridgegen contract to filter for logs related to the TEESignatureVerified events
30+
// If any of these events are encountered, it checks the log iterator for the data about this event.
31+
// Return:
32+
// returns the Hotshot height of the last event in the iterator returned from FilterTEESignatureVerified()
33+
// representing the most recently emitted hotshotblock height. Any errors encountered will result in 0 being returned.
34+
func (b *BatchPoster) fetchHotshotBlockFromLastCheckpoint(ctx context.Context) uint64 {
35+
pollingStep := b.config().EspressoEventPollingStep
36+
header, err := b.l1Reader.LastHeader(ctx)
37+
if err != nil {
38+
log.Error("Failed to fetch last header from parent chain", "err", err)
39+
return 0
40+
}
41+
42+
var lastHotshotHeight uint64 = 0
43+
// Prevent unsigned integer underflow: in Go, subtracting a larger value
44+
// from a smaller uint64 will wrap around to a very large number.
45+
for i := header.Number.Uint64(); i >= b.config().HotShotFirstPostingBlock; i -= min(i, pollingStep) {
46+
start := i - min(i, pollingStep)
47+
if start < b.config().HotShotFirstPostingBlock {
48+
start = b.config().HotShotFirstPostingBlock
49+
}
50+
filterOpts := bind.FilterOpts{
51+
Start: start,
52+
End: &i,
53+
Context: ctx,
54+
}
55+
56+
logIterator, err := b.seqInbox.FilterTEESignatureVerified(&filterOpts, []*big.Int{}, []*big.Int{})
57+
if err != nil {
58+
log.Error("Failed to obtain iterator for logs for block", "blockNumber", i, "err", err)
59+
continue
60+
}
61+
62+
if logIterator == nil {
63+
continue
64+
}
65+
66+
for logIterator.Next() {
67+
lastHotshotHeight = logIterator.Event.HotshotHeight.Uint64()
68+
}
69+
70+
if lastHotshotHeight > 0 {
71+
return lastHotshotHeight
72+
}
73+
}
74+
75+
log.Warn("No logs found for Hotshot block")
76+
return 0
77+
}
78+
79+
func setupNitroVerifier(teeVerifier *espressogen.IEspressoTEEVerifier, l1Client *ethclient.Client) (espressotee.EspressoNitroTEEVerifierInterface, error) {
80+
// Setup nitro contract interface
81+
nitroAddr, err := teeVerifier.EspressoNitroTEEVerifier(&bind.CallOpts{})
82+
if err != nil {
83+
return nil, fmt.Errorf("failed to get nitro tee verifier address from caller: %w", err)
84+
}
85+
log.Info("successfully retrieved nitro contract verifier address", "address", nitroAddr)
86+
87+
nitroVerifierBindings, err := espressogen.NewIEspressoNitroTEEVerifier(
88+
nitroAddr,
89+
l1Client)
90+
if err != nil {
91+
return nil, err
92+
}
93+
nitroVerifier := espressotee.NewEspressoNitroTEEVerifier(nitroVerifierBindings, l1Client, nitroAddr)
94+
return nitroVerifier, nil
95+
}

arbnode/espresso_batcher_addr_monitor.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ func NewBatcherAddrMonitor(
8686
l1Reader *headerreader.HeaderReader,
8787
seqInboxAddr common.Address,
8888
deployAt uint64,
89-
fromBlock uint64,
89+
fromParentBlock uint64,
9090
) *BatcherAddrMonitor {
9191
seqInboxInterface, err := bridgegen.NewSequencerInbox(seqInboxAddr, l1Reader.Client())
9292
if err != nil {
9393
panic(err)
9494
}
95-
if fromBlock < deployAt+1 {
96-
fromBlock = deployAt + 1
95+
if fromParentBlock < deployAt+1 {
96+
fromParentBlock = deployAt + 1
9797
}
9898
return &BatcherAddrMonitor{
9999
initAddresses: initAddresses,
@@ -102,7 +102,7 @@ func NewBatcherAddrMonitor(
102102
seqInboxAddr: seqInboxAddr,
103103
seqInboxInterface: seqInboxInterface,
104104
deployAt: deployAt,
105-
lastProcessedParentHeight: fromBlock - 1,
105+
lastProcessedParentHeight: fromParentBlock - 1,
106106
}
107107
}
108108

arbnode/espresso_transaction_streamer_helpers.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ func ConfigureEspressoFields(
200200
TxnsResubmissionInterval: DefaultBatchPosterConfig.EspressoTxnsResubmissionInterval,
201201
MaxTransactionSize: DefaultBatchPosterConfig.EspressoTxSizeLimit,
202202
ResubmitEspressoTxDeadline: DefaultBatchPosterConfig.ResubmitEspressoTxDeadline,
203-
UseEscapeHatch: DefaultBatchPosterConfig.UseEscapeHatch,
204203

205204
SubmitterCreator: submitter.NewPollingEspressoSubmitter,
206205
}
@@ -220,10 +219,7 @@ func ConfigureEspressoFields(
220219
submitter.WithTxnsSendingInterval(config.TxnsSendingInterval),
221220
submitter.WithTxnsResubmissionInterval(config.TxnsResubmissionInterval),
222221
submitter.WithResubmitEspressoTxDeadline(config.ResubmitEspressoTxDeadline),
223-
submitter.WithUseEscapeHatch(config.UseEscapeHatch),
224-
submitter.WithEscapeHatchEnabled(config.EscapeHatchEnabled),
225222
submitter.WithMaxTransactionSize(config.MaxTransactionSize),
226-
submitter.WithMaxBlockLagBeforeEscapeHatch(config.MaxBlockLagBeforeEscapeHatch),
227223
submitter.WithInitialFinalizedSequencerMessageCount(config.InitialFinalizedSequencerMessageCount),
228224
submitter.WithMultipleOptions(config.SubmitterConfiguration...),
229225
)

arbnode/espresso_utils.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ package arbnode
22

33
import (
44
"context"
5+
6+
"github.com/ethereum/go-ethereum/common"
7+
"github.com/ethereum/go-ethereum/crypto"
8+
9+
"github.com/offchainlabs/nitro/util/signature"
510
)
611

712
var (
@@ -34,3 +39,21 @@ func binarySearchForBlockNumber(
3439
}
3540
return start, nil
3641
}
42+
43+
// We should be able to get the address as soon as we have the signer.
44+
// We don't want to change a lot of code to make this work since we are working on a forked repo.
45+
// This function is not costly and it should be called only once.
46+
func recoverAddressFromSigner(signer signature.DataSignerFunc) (common.Address, error) {
47+
message := make([]byte, 32)
48+
signature, err := signer(message)
49+
if err != nil {
50+
return common.Address{}, err
51+
}
52+
53+
publicKey, err := crypto.SigToPub(message, signature)
54+
if err != nil {
55+
return common.Address{}, err
56+
}
57+
58+
return crypto.PubkeyToAddress(*publicKey), nil
59+
}

arbnode/espresso_utils_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package arbnode
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/ethereum/go-ethereum/crypto"
8+
9+
"github.com/offchainlabs/nitro/util/signature"
10+
)
11+
12+
func TestRecoverAddressFromSigner(t *testing.T) {
13+
privateKey, err := crypto.GenerateKey()
14+
if err != nil {
15+
t.Fatal(err)
16+
}
17+
address, err := recoverAddressFromSigner(signature.DataSignerFromPrivateKey(privateKey))
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
if address != crypto.PubkeyToAddress(privateKey.PublicKey) {
22+
t.Fatalf("expected address %v, got %v", crypto.PubkeyToAddress(privateKey.PublicKey), address)
23+
}
24+
}
25+
26+
func TestBinarySearchForBlockNumber(t *testing.T) {
27+
target := uint64(64)
28+
count := 0
29+
ctx := context.Background()
30+
start := uint64(0)
31+
end := uint64(100)
32+
f := func(ctx context.Context, blockNumber uint64) (int, error) {
33+
count++
34+
if blockNumber < target {
35+
return -1, nil
36+
} else if blockNumber > target {
37+
return 1, nil
38+
}
39+
return 0, nil
40+
}
41+
result, err := binarySearchForBlockNumber(ctx, start, end, f)
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
if result != target {
46+
t.Fatalf("expected result %d, got %d", target, result)
47+
}
48+
if count > 7 {
49+
t.Fatalf("expected count less than %d, got %d", 7, count)
50+
}
51+
52+
targetRangeStart := uint64(60)
53+
targetRangeEnd := uint64(70)
54+
count = 0
55+
f = func(ctx context.Context, blockNumber uint64) (int, error) {
56+
count++
57+
if blockNumber < targetRangeStart {
58+
return -1, nil
59+
} else if blockNumber > targetRangeEnd {
60+
return 1, nil
61+
}
62+
return 0, nil
63+
}
64+
result, err = binarySearchForBlockNumber(ctx, start, end, f)
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
if result != targetRangeStart {
69+
t.Fatalf("expected result %d, got %d", targetRangeStart, result)
70+
}
71+
if count > 7 {
72+
t.Fatalf("expected count less than %d, got %d", 7, count)
73+
}
74+
}

arbnode/node.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ func getBatchPoster(
916916
dapReaders []daprovider.Reader,
917917
stakerAddr common.Address,
918918
dataSigner signature.DataSignerFunc,
919+
l2ChainId uint64,
919920
) (*BatchPoster, error) {
920921
var batchPoster *BatchPoster
921922
if config.BatchPoster.Enable {
@@ -931,6 +932,7 @@ func getBatchPoster(
931932
}
932933
var err error
933934
batchPoster, err = NewBatchPoster(ctx, &BatchPosterOpts{
935+
ChainID: l2ChainId,
934936
DataPosterDB: rawdb.NewTable(arbDb, storage.BatchPosterPrefix),
935937
L1Reader: l1Reader,
936938
Inbox: inboxTracker,
@@ -1201,7 +1203,7 @@ func createNodeImpl(
12011203
return nil, err
12021204
}
12031205

1204-
batchPoster, err := getBatchPoster(ctx, config, configFetcher, txOptsBatchPoster, dapWriter, l1Reader, inboxTracker, txStreamer, executionBatchPoster, arbDb, syncMonitor, deployInfo, parentChainID, dapReaders, stakerAddr, dataSigner)
1206+
batchPoster, err := getBatchPoster(ctx, config, configFetcher, txOptsBatchPoster, dapWriter, l1Reader, inboxTracker, txStreamer, executionBatchPoster, arbDb, syncMonitor, deployInfo, parentChainID, dapReaders, stakerAddr, dataSigner, l2Config.ChainID.Uint64())
12051207
if err != nil {
12061208
return nil, err
12071209
}

0 commit comments

Comments
 (0)