Skip to content

Commit 1633071

Browse files
author
rian
committed
bootstrap
1 parent f97b848 commit 1633071

9 files changed

+53843
-69
lines changed

builder/builder.go

+79-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/NethermindEth/juno/feed"
1616
"github.com/NethermindEth/juno/mempool"
1717
"github.com/NethermindEth/juno/service"
18+
"github.com/NethermindEth/juno/starknetdata"
1819
"github.com/NethermindEth/juno/sync"
1920
"github.com/NethermindEth/juno/utils"
2021
"github.com/NethermindEth/juno/vm"
@@ -42,6 +43,10 @@ type Builder struct {
4243
pendingBlock blockchain.Pending
4344
headState core.StateReader
4445
headCloser blockchain.StateCloser
46+
47+
bootstrap bool
48+
bootstrapToBlock uint64
49+
starknetData starknetdata.StarknetData
4550
}
4651

4752
func New(privKey *ecdsa.PrivateKey, ownAddr *felt.Felt, bc *blockchain.Blockchain, builderVM vm.VM,
@@ -66,12 +71,54 @@ func (b *Builder) WithEventListener(l EventListener) *Builder {
6671
return b
6772
}
6873

74+
func (b *Builder) WithBootstrap(bootstrap bool) *Builder {
75+
b.bootstrap = bootstrap
76+
return b
77+
}
78+
79+
func (b *Builder) WithStarknetData(starknetData starknetdata.StarknetData) *Builder {
80+
b.starknetData = starknetData
81+
return b
82+
}
83+
84+
func (b *Builder) WithBootstrapToBlock(bootstrapToBlock uint64) *Builder {
85+
b.bootstrapToBlock = bootstrapToBlock
86+
return b
87+
}
88+
89+
func (b *Builder) BootstrapSeq(ctx context.Context, toBlockNum uint64) error {
90+
var i uint64
91+
for i = 0; i < toBlockNum; i++ {
92+
b.log.Infow("Sequencer, syncing block", "blockNumber", 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 {
@@ -141,10 +189,10 @@ func (b *Builder) Finalise() error {
141189
b.pendingBlock.Block.Hash.ShortString(), "state", b.pendingBlock.Block.GlobalStateRoot.ShortString())
142190
b.listener.OnBlockFinalised(b.pendingBlock.Block.Header)
143191

144-
if err := b.clearPending(); err != nil {
192+
if err := b.ClearPending(); err != nil {
145193
return err
146194
}
147-
return b.initPendingBlock()
195+
return b.InitPendingBlock()
148196
}
149197

150198
// ValidateAgainstPendingState validates a user transaction against the pending state
@@ -261,7 +309,6 @@ func (b *Builder) depletePool(ctx context.Context) error {
261309
if !errors.As(err, &txnExecutionError) {
262310
return err
263311
}
264-
265312
b.log.Debugw("failed txn", "hash", userTxn.Transaction.Hash().String(), "err", err.Error())
266313
}
267314

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

builder/builder_test.go

+101
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,104 @@ func TestBuildBlocks(t *testing.T) {
378378
}
379379
require.Equal(t, uint64(90), totalTxns)
380380
}
381+
382+
func TestSepoliaBootstrap(t *testing.T) {
383+
mockCtrl := gomock.NewController(t)
384+
bc := blockchain.New(pebble.NewMemTest(t), &utils.Sepolia)
385+
snData := mocks.NewMockStarknetData(mockCtrl)
386+
p := mempool.New(pebble.NewMemTest(t))
387+
vmm := vm.New(utils.NewNopZapLogger())
388+
seqAddr := utils.HexToFelt(t, "0xDEADBEEF")
389+
privKey, err := ecdsa.GenerateKey(rand.Reader)
390+
require.NoError(t, err)
391+
392+
blockTime := time.Second
393+
testBuilder := builder.New(privKey, seqAddr, bc, vmm, blockTime, p, utils.NewNopZapLogger()).
394+
WithBootstrapToBlock(2).
395+
WithStarknetData(snData).
396+
WithBootstrap(true)
397+
398+
client := feeder.NewTestClient(t, &utils.Sepolia)
399+
gw := adaptfeeder.New(client)
400+
401+
var i uint64
402+
var block *core.Block
403+
var err2 error
404+
for i = 0; i < 2; i++ {
405+
block, err2 = gw.BlockByNumber(context.Background(), i)
406+
require.NoError(t, err2)
407+
408+
su, err2 := gw.StateUpdate(context.Background(), i)
409+
require.NoError(t, err2)
410+
411+
snData.EXPECT().BlockByNumber(context.Background(), i).Return(block, nil)
412+
snData.EXPECT().StateUpdate(context.Background(), i).Return(su, nil)
413+
}
414+
classHashes := []string{
415+
"0x5c478ee27f2112411f86f207605b2e2c58cdb647bac0df27f660ef2252359c6",
416+
"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3",
417+
"0x1b661756bf7d16210fc611626e1af4569baa1781ffc964bd018f4585ae241c1",
418+
}
419+
420+
for _, hash := range classHashes {
421+
classHash := utils.HexToFelt(t, hash)
422+
class, err2 := gw.Class(context.Background(), classHash)
423+
require.NoError(t, err2)
424+
snData.EXPECT().Class(context.Background(), classHash).Return(class, nil)
425+
}
426+
427+
t.Run("Bootstrap", func(t *testing.T) {
428+
err = testBuilder.BootstrapSeq(context.Background(), uint64(2))
429+
require.NoError(t, err)
430+
head, err := bc.BlockByNumber(1)
431+
require.NoError(t, err)
432+
require.Equal(t, uint64(1), head.Number)
433+
require.Equal(t, block.TransactionCount, head.TransactionCount, "TransactionCount diff")
434+
require.Equal(t, block.GlobalStateRoot.String(), head.GlobalStateRoot.String(), "GlobalStateRoot diff")
435+
})
436+
437+
t.Run("Bootstrap blocks 0 and 1 + Run block 2", func(t *testing.T) {
438+
block, err := gw.BlockByNumber(context.Background(), 2)
439+
require.NoError(t, err)
440+
txns := block.Transactions
441+
var mempoolTxns []*mempool.BroadcastedTransaction
442+
for _, txn := range txns {
443+
switch tx := txn.(type) {
444+
case *core.DeployTransaction, *core.DeployAccountTransaction, *core.InvokeTransaction, *core.L1HandlerTransaction:
445+
mempoolTxns = append(mempoolTxns,
446+
&mempool.BroadcastedTransaction{
447+
Transaction: tx,
448+
})
449+
case *core.DeclareTransaction:
450+
class, err2 := gw.Class(context.Background(), tx.ClassHash)
451+
require.NoError(t, err2)
452+
mempoolTxns = append(mempoolTxns, &mempool.BroadcastedTransaction{
453+
Transaction: tx,
454+
DeclaredClass: class,
455+
})
456+
default:
457+
require.Error(t, errors.New("unknown transaction type"))
458+
}
459+
}
460+
461+
for _, txn := range mempoolTxns {
462+
err = p.Push(txn)
463+
require.NoError(t, err)
464+
}
465+
466+
ctx, cancel := context.WithTimeout(context.Background(), 2*blockTime)
467+
defer cancel()
468+
err = testBuilder.Run(ctx)
469+
require.NoError(t, err)
470+
head, err := bc.BlockByNumber(1)
471+
require.NoError(t, err)
472+
require.Equal(t, uint64(1), head.Number)
473+
require.Equal(t, block.TransactionCount, head.TransactionCount, "TransactionCount diff")
474+
require.Equal(t, block.GlobalStateRoot.String(), head.GlobalStateRoot.String(), "GlobalStateRoot diff")
475+
head, err = bc.Head()
476+
require.NoError(t, err)
477+
require.Equal(t, block.Number, head.Number)
478+
require.Equal(t, block.TransactionCount, head.TransactionCount)
479+
require.Equal(t, head.GlobalStateRoot, head.GlobalStateRoot)
480+
})
481+
}

0 commit comments

Comments
 (0)