Skip to content

Commit 65cef8b

Browse files
author
rian
committed
bootstrap
1 parent f97b848 commit 65cef8b

7 files changed

+46639
-42
lines changed

builder/builder.go

+81-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package builder
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
stdsync "sync"
78
"time"
89

@@ -15,6 +16,7 @@ import (
1516
"github.com/NethermindEth/juno/feed"
1617
"github.com/NethermindEth/juno/mempool"
1718
"github.com/NethermindEth/juno/service"
19+
"github.com/NethermindEth/juno/starknetdata"
1820
"github.com/NethermindEth/juno/sync"
1921
"github.com/NethermindEth/juno/utils"
2022
"github.com/NethermindEth/juno/vm"
@@ -42,6 +44,10 @@ type Builder struct {
4244
pendingBlock blockchain.Pending
4345
headState core.StateReader
4446
headCloser blockchain.StateCloser
47+
48+
bootstrap bool
49+
bootstrapToBlock uint64
50+
starknetData starknetdata.StarknetData // To bootstrap sequencer
4551
}
4652

4753
func New(privKey *ecdsa.PrivateKey, ownAddr *felt.Felt, bc *blockchain.Blockchain, builderVM vm.VM,
@@ -66,12 +72,53 @@ func (b *Builder) WithEventListener(l EventListener) *Builder {
6672
return b
6773
}
6874

75+
func (b *Builder) WithBootstrap(bootstrap bool) *Builder {
76+
b.bootstrap = bootstrap
77+
return b
78+
}
79+
80+
func (b *Builder) WithStarknetData(starknetData starknetdata.StarknetData) *Builder {
81+
b.starknetData = starknetData
82+
return b
83+
}
84+
85+
func (b *Builder) WithBootstrapToBlock(bootstrapToBlock uint64) *Builder {
86+
b.bootstrapToBlock = bootstrapToBlock
87+
return b
88+
}
89+
90+
func (b *Builder) BootstrapSeq(ctx context.Context, toBlockNum uint64) error {
91+
var i uint64
92+
for i = 0; i < toBlockNum; i++ {
93+
block, su, classes, err := b.getSyncData(i)
94+
if err != nil {
95+
return err
96+
}
97+
commitments, err := b.bc.SanityCheckNewHeight(block, su, classes)
98+
if err != nil {
99+
return err
100+
}
101+
err = b.bc.Store(block, commitments, su, classes)
102+
if err != nil {
103+
return err
104+
}
105+
}
106+
return nil
107+
}
108+
69109
func (b *Builder) Run(ctx context.Context) error {
70-
if err := b.initPendingBlock(); err != nil {
110+
if b.bootstrap {
111+
err := b.BootstrapSeq(ctx, b.bootstrapToBlock)
112+
if err != nil {
113+
return err
114+
}
115+
}
116+
117+
if err := b.InitPendingBlock(); err != nil {
71118
return err
72119
}
73120
defer func() {
74-
if pErr := b.clearPending(); pErr != nil {
121+
if pErr := b.ClearPending(); pErr != nil {
75122
b.log.Errorw("clearing pending", "err", pErr)
76123
}
77124
}()
@@ -90,14 +137,15 @@ func (b *Builder) Run(ctx context.Context) error {
90137
<-doneListen
91138
return nil
92139
case <-time.After(b.blockTime):
140+
b.log.Debugw("Finalising new block")
93141
if err := b.Finalise(); err != nil {
94142
return err
95143
}
96144
}
97145
}
98146
}
99147

100-
func (b *Builder) initPendingBlock() error {
148+
func (b *Builder) InitPendingBlock() error {
101149
if b.pendingBlock.Block != nil {
102150
return nil
103151
}
@@ -117,7 +165,7 @@ func (b *Builder) initPendingBlock() error {
117165
return err
118166
}
119167

120-
func (b *Builder) clearPending() error {
168+
func (b *Builder) ClearPending() error {
121169
b.pendingBlock = blockchain.Pending{}
122170
if b.headState != nil {
123171
if err := b.headCloser(); err != nil {
@@ -137,14 +185,16 @@ func (b *Builder) Finalise() error {
137185
if err := b.bc.Finalise(&b.pendingBlock, b.Sign); err != nil {
138186
return err
139187
}
188+
fmt.Sprintln("Finalised block", "number", b.pendingBlock.Block.Number, "hash",
189+
b.pendingBlock.Block.Hash.ShortString(), "state", b.pendingBlock.Block.GlobalStateRoot.ShortString())
140190
b.log.Infow("Finalised block", "number", b.pendingBlock.Block.Number, "hash",
141191
b.pendingBlock.Block.Hash.ShortString(), "state", b.pendingBlock.Block.GlobalStateRoot.ShortString())
142192
b.listener.OnBlockFinalised(b.pendingBlock.Block.Header)
143193

144-
if err := b.clearPending(); err != nil {
194+
if err := b.ClearPending(); err != nil {
145195
return err
146196
}
147-
return b.initPendingBlock()
197+
return b.InitPendingBlock()
148198
}
149199

150200
// ValidateAgainstPendingState validates a user transaction against the pending state
@@ -261,7 +311,6 @@ func (b *Builder) depletePool(ctx context.Context) error {
261311
if !errors.As(err, &txnExecutionError) {
262312
return err
263313
}
264-
265314
b.log.Debugw("failed txn", "hash", userTxn.Transaction.Hash().String(), "err", err.Error())
266315
}
267316

@@ -311,3 +360,28 @@ func (b *Builder) runTxn(txn *mempool.BroadcastedTransaction) error {
311360
b.pendingBlock.Block.EventCount += uint64(len(receipt.Events))
312361
return nil
313362
}
363+
364+
func (b *Builder) getSyncData(blockNumber uint64) (*core.Block, *core.StateUpdate,
365+
map[felt.Felt]core.Class, error,
366+
) {
367+
block, err := b.starknetData.BlockByNumber(context.Background(), blockNumber)
368+
if err != nil {
369+
return nil, nil, nil, err
370+
}
371+
su, err := b.starknetData.StateUpdate(context.Background(), blockNumber)
372+
if err != nil {
373+
return nil, nil, nil, err
374+
}
375+
txns := block.Transactions
376+
classes := make(map[felt.Felt]core.Class)
377+
for _, txn := range txns {
378+
if t, ok := txn.(*core.DeclareTransaction); ok {
379+
class, err := b.starknetData.Class(context.Background(), t.ClassHash)
380+
if err != nil {
381+
return nil, nil, nil, err
382+
}
383+
classes[*t.ClassHash] = class
384+
}
385+
}
386+
return block, su, classes, nil
387+
}

builder/builder_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,57 @@ func TestBuildBlocks(t *testing.T) {
378378
}
379379
require.Equal(t, uint64(90), totalTxns)
380380
}
381+
382+
func TestSepoliaBuildBlocks(t *testing.T) {
383+
mockCtrl := gomock.NewController(t)
384+
bc := blockchain.New(pebble.NewMemTest(t), &utils.Sepolia)
385+
snData := mocks.NewMockStarknetData(mockCtrl)
386+
387+
seqAddr := utils.HexToFelt(t, "0xDEADBEEF")
388+
privKey, err := ecdsa.GenerateKey(rand.Reader)
389+
require.NoError(t, err)
390+
391+
blockTime := time.Millisecond
392+
testBuilder := builder.New(privKey, seqAddr, bc, nil, blockTime, nil, utils.NewNopZapLogger()).
393+
WithBootstrapToBlock(2).
394+
WithStarknetData(snData).
395+
WithBootstrap(true)
396+
397+
client := feeder.NewTestClient(t, &utils.Sepolia)
398+
gw := adaptfeeder.New(client)
399+
400+
var i uint64
401+
var block *core.Block
402+
var err2 error
403+
for i = 0; i < 2; i++ {
404+
block, err2 = gw.BlockByNumber(context.Background(), i)
405+
require.NoError(t, err2)
406+
407+
su, err2 := gw.StateUpdate(context.Background(), i)
408+
require.NoError(t, err2)
409+
410+
snData.EXPECT().BlockByNumber(context.Background(), i).Return(block, nil)
411+
snData.EXPECT().StateUpdate(context.Background(), i).Return(su, nil)
412+
}
413+
classHashes := []string{
414+
"0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6",
415+
"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3",
416+
"0x1b661756bf7d16210fc611626e1af4569baa1781ffc964bd018f4585ae241c1",
417+
}
418+
419+
for _, hash := range classHashes {
420+
classHash := utils.HexToFelt(t, hash)
421+
class, err2 := gw.Class(context.Background(), classHash)
422+
require.NoError(t, err2)
423+
snData.EXPECT().Class(context.Background(), classHash).Return(class, nil)
424+
}
425+
426+
err = testBuilder.BootstrapSeq(context.Background(), uint64(2))
427+
require.NoError(t, err)
428+
429+
head, err := bc.BlockByNumber(1)
430+
require.NoError(t, err)
431+
require.Equal(t, uint64(1), head.Number)
432+
require.Equal(t, block.TransactionCount, head.TransactionCount, "TransactionCount diff")
433+
require.Equal(t, block.GlobalStateRoot.String(), head.GlobalStateRoot.String(), "GlobalStateRoot diff")
434+
}

0 commit comments

Comments
 (0)