diff --git a/builder/bootstrap.go b/builder/bootstrap.go new file mode 100644 index 0000000000..fb745b12e9 --- /dev/null +++ b/builder/bootstrap.go @@ -0,0 +1,60 @@ +package builder + +import ( + "context" + "errors" + + "github.com/NethermindEth/juno/core" + "github.com/NethermindEth/juno/mempool" +) + +// bootstrap submits transactions inside a block directly into the mempool +// this allows us to bootstrap the network with unsupported transactions +func (b *Builder) bootstrapChain() error { + if b.starknetData == nil { + return errors.New("can't bootstrap if the network isn't specified") + } + for i := 0; i < int(b.bootstrapToBlock); i++ { + txns, err := getTxns(b, uint64(i)) + if err != nil { + return err + } + for _, txn := range txns { + b.pool.Push(txn) + } + if err := b.Finalise(); err != nil { + return err + } + } + return nil +} + +func getTxns(builder *Builder, blockNumber uint64) ([]*mempool.BroadcastedTransaction, error) { + var mempoolTxns []*mempool.BroadcastedTransaction + block, err := builder.starknetData.BlockByNumber(context.Background(), blockNumber) + if err != nil { + return nil, err + } + txns := block.Transactions + for _, txn := range txns { + switch t := txn.(type) { + case *core.DeployTransaction, *core.DeployAccountTransaction, *core.InvokeTransaction, *core.L1HandlerTransaction: + mempoolTxns = append(mempoolTxns, + &mempool.BroadcastedTransaction{ + Transaction: t, + }) + case *core.DeclareTransaction: + class, err := builder.starknetData.Class(context.Background(), t.ClassHash) + if err != nil { + return nil, err + } + mempoolTxns = append(mempoolTxns, &mempool.BroadcastedTransaction{ + Transaction: t, + DeclaredClass: class, + }) + default: + return nil, errors.New("unknown transaction") + } + } + return mempoolTxns, nil +} diff --git a/builder/builder.go b/builder/builder.go index d559b39b52..b4bb873269 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -15,6 +15,7 @@ import ( "github.com/NethermindEth/juno/feed" "github.com/NethermindEth/juno/mempool" "github.com/NethermindEth/juno/service" + "github.com/NethermindEth/juno/starknetdata" "github.com/NethermindEth/juno/sync" "github.com/NethermindEth/juno/utils" "github.com/NethermindEth/juno/vm" @@ -42,6 +43,10 @@ type Builder struct { pendingBlock blockchain.Pending headState core.StateReader headCloser blockchain.StateCloser + + bootstrap bool + bootstrapToBlock uint64 + starknetData starknetdata.StarknetData // To bootstrap sequencer } func New(privKey *ecdsa.PrivateKey, ownAddr *felt.Felt, bc *blockchain.Blockchain, builderVM vm.VM, @@ -66,6 +71,16 @@ func (b *Builder) WithEventListener(l EventListener) *Builder { return b } +func (b *Builder) WithBootstrap(bootstrap bool) *Builder { + b.bootstrap = bootstrap + return b +} + +func (b *Builder) WithStarknetData(starknetData starknetdata.StarknetData) *Builder { + b.starknetData = starknetData + return b +} + func (b *Builder) Run(ctx context.Context) error { if err := b.initPendingBlock(); err != nil { return err @@ -84,6 +99,12 @@ func (b *Builder) Run(ctx context.Context) error { close(doneListen) }() + if b.bootstrap { + if err := b.bootstrapChain(); err != nil { + return err + } + } + for { select { case <-ctx.Done(): diff --git a/node/node.go b/node/node.go index 1c3dd35f3c..e047d8590f 100644 --- a/node/node.go +++ b/node/node.go @@ -151,22 +151,24 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen nodeVM := vm.New(log) throttledVM := NewThrottledVM(nodeVM, cfg.MaxVMs, int32(cfg.MaxVMQueue)) + client := feeder.NewClient(cfg.Network.FeederURL).WithUserAgent(ua).WithLogger(log). + WithTimeout(cfg.GatewayTimeout).WithAPIKey(cfg.GatewayAPIKey) + starknetData := adaptfeeder.New(client) var rpcHandler *rpc.Handler if cfg.Sequencer { pKey, kErr := ecdsa.GenerateKey(rand.Reader) if kErr != nil { return nil, kErr } - poolDB, _ := pebble.NewMem() p := mempool.New(poolDB) - sequencer := builder.New(pKey, new(felt.Felt).SetUint64(1337), chain, nodeVM, time.Second*time.Duration(cfg.SeqBlockTime), p, log) //nolint: gomnd + sequencer := builder.New(pKey, new(felt.Felt).SetUint64(1337), chain, nodeVM, time.Second*time.Duration(cfg.SeqBlockTime), p, //nolint: gomnd + log).WithBootstrap(true).WithStarknetData(starknetData) rpcHandler = rpc.New(chain, sequencer, throttledVM, version, &cfg.Network, log).WithMempool(p) services = append(services, sequencer) } else { - client := feeder.NewClient(cfg.Network.FeederURL).WithUserAgent(ua).WithLogger(log). - WithTimeout(cfg.GatewayTimeout).WithAPIKey(cfg.GatewayAPIKey) - synchronizer := sync.New(chain, adaptfeeder.New(client), log, cfg.PendingPollInterval, dbIsRemote) + + synchronizer := sync.New(chain, starknetData, log, cfg.PendingPollInterval, dbIsRemote) gatewayClient := gateway.NewClient(cfg.Network.GatewayURL, log).WithUserAgent(ua).WithAPIKey(cfg.GatewayAPIKey) var p2pService *p2p.Service