// Copyright 2021 The Swarm Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package node import ( "context" "fmt" "io" "log" "math/big" "net" "net/http" "time" "github.com/ethereum/go-ethereum/common" mockAccounting "github.com/ethersphere/bee/pkg/accounting/mock" "github.com/ethersphere/bee/pkg/api" "github.com/ethersphere/bee/pkg/bzz" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/debugapi" "github.com/ethersphere/bee/pkg/feeds/factory" "github.com/ethersphere/bee/pkg/localstore" "github.com/ethersphere/bee/pkg/logging" mockP2P "github.com/ethersphere/bee/pkg/p2p/mock" mockPingPong "github.com/ethersphere/bee/pkg/pingpong/mock" "github.com/ethersphere/bee/pkg/pinning" "github.com/ethersphere/bee/pkg/postage" "github.com/ethersphere/bee/pkg/postage/batchstore" mockPost "github.com/ethersphere/bee/pkg/postage/mock" "github.com/ethersphere/bee/pkg/postage/postagecontract" mockPostContract "github.com/ethersphere/bee/pkg/postage/postagecontract/mock" postagetesting "github.com/ethersphere/bee/pkg/postage/testing" "github.com/ethersphere/bee/pkg/pss" "github.com/ethersphere/bee/pkg/pushsync" mockPushsync "github.com/ethersphere/bee/pkg/pushsync/mock" "github.com/ethersphere/bee/pkg/settlement/pseudosettle" "github.com/ethersphere/bee/pkg/settlement/swap/chequebook" mockchequebook "github.com/ethersphere/bee/pkg/settlement/swap/chequebook/mock" swapmock "github.com/ethersphere/bee/pkg/settlement/swap/mock" "github.com/ethersphere/bee/pkg/statestore/leveldb" mockStateStore "github.com/ethersphere/bee/pkg/statestore/mock" "github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/bee/pkg/tags" "github.com/ethersphere/bee/pkg/topology/lightnode" mockTopology "github.com/ethersphere/bee/pkg/topology/mock" "github.com/ethersphere/bee/pkg/tracing" "github.com/ethersphere/bee/pkg/transaction" transactionmock "github.com/ethersphere/bee/pkg/transaction/mock" "github.com/ethersphere/bee/pkg/traversal" "github.com/hashicorp/go-multierror" "github.com/multiformats/go-multiaddr" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) type DevBee struct { tracerCloser io.Closer stateStoreCloser io.Closer localstoreCloser io.Closer apiCloser io.Closer pssCloser io.Closer tagsCloser io.Closer errorLogWriter *io.PipeWriter apiServer *http.Server debugAPIServer *http.Server } type DevOptions struct { Logger logging.Logger APIAddr string DebugAPIAddr string CORSAllowedOrigins []string DBOpenFilesLimit uint64 ReserveCapacity uint64 DBWriteBufferSize uint64 DBBlockCacheCapacity uint64 DBDisableSeeksCompaction bool } // NewDevBee starts the bee instance in 'development' mode // this implies starting an API and a Debug endpoints while mocking all their services. func NewDevBee(logger logging.Logger, o *DevOptions) (b *DevBee, err error) { tracer, tracerCloser, err := tracing.NewTracer(&tracing.Options{ Enabled: false, }) if err != nil { return nil, fmt.Errorf("tracer: %w", err) } b = &DevBee{ errorLogWriter: logger.WriterLevel(logrus.ErrorLevel), tracerCloser: tracerCloser, } stateStore, err := leveldb.NewInMemoryStateStore(logger) if err != nil { return nil, err } b.stateStoreCloser = stateStore mockKey, err := crypto.GenerateSecp256k1Key() if err != nil { return nil, err } signer := crypto.NewDefaultSigner(mockKey) overlayEthAddress, err := signer.EthereumAddress() if err != nil { return nil, fmt.Errorf("eth address: %w", err) } var debugAPIService *debugapi.Service if o.DebugAPIAddr != "" { debugAPIListener, err := net.Listen("tcp", o.DebugAPIAddr) if err != nil { return nil, fmt.Errorf("debug api listener: %w", err) } var mockTransaction = transactionmock.New(transactionmock.WithPendingTransactionsFunc(func() ([]common.Hash, error) { return []common.Hash{common.HexToHash("abcd")}, nil }), transactionmock.WithResendTransactionFunc(func(ctx context.Context, txHash common.Hash) error { return nil }), transactionmock.WithStoredTransactionFunc(func(txHash common.Hash) (*transaction.StoredTransaction, error) { recipient := common.HexToAddress("dfff") return &transaction.StoredTransaction{ To: &recipient, Created: 1, Data: []byte{1, 2, 3, 4}, GasPrice: big.NewInt(12), GasLimit: 5345, Value: big.NewInt(4), Nonce: 3, Description: "test", }, nil }), transactionmock.WithCancelTransactionFunc(func(ctx context.Context, originalTxHash common.Hash) (common.Hash, error) { return common.Hash{}, nil }), ) debugAPIService = debugapi.New(mockKey.PublicKey, mockKey.PublicKey, overlayEthAddress, logger, tracer, nil, big.NewInt(0), mockTransaction) debugAPIServer := &http.Server{ IdleTimeout: 30 * time.Second, ReadHeaderTimeout: 3 * time.Second, Handler: debugAPIService, ErrorLog: log.New(b.errorLogWriter, "", 0), } go func() { logger.Infof("debug api address: %s", debugAPIListener.Addr()) if err := debugAPIServer.Serve(debugAPIListener); err != nil && err != http.ErrServerClosed { logger.Debugf("debug api server: %v", err) logger.Error("unable to serve debug api") } }() b.debugAPIServer = debugAPIServer } lo := &localstore.Options{ Capacity: 1000, ReserveCapacity: o.ReserveCapacity, OpenFilesLimit: o.DBOpenFilesLimit, BlockCacheCapacity: o.DBBlockCacheCapacity, WriteBufferSize: o.DBWriteBufferSize, DisableSeeksCompaction: o.DBDisableSeeksCompaction, UnreserveFunc: func(postage.UnreserveIteratorFn) error { return nil }, } var swarmAddress swarm.Address storer, err := localstore.New("", swarmAddress.Bytes(), stateStore, lo, logger) if err != nil { return nil, fmt.Errorf("localstore: %w", err) } b.localstoreCloser = storer tagService := tags.NewTags(stateStore, logger) b.tagsCloser = tagService pssService := pss.New(mockKey, logger) b.pssCloser = pssService pssService.SetPushSyncer(mockPushsync.New(func(ctx context.Context, chunk swarm.Chunk) (*pushsync.Receipt, error) { pssService.TryUnwrap(chunk) return &pushsync.Receipt{}, nil })) traversalService := traversal.New(storer) pinningService := pinning.NewService(storer, stateStore, traversalService) batchStore, err := batchstore.New(stateStore, func(b []byte) error { return nil }, logger) if err != nil { return nil, fmt.Errorf("batchstore: %w", err) } post := mockPost.New() postageContract := mockPostContract.New( mockPostContract.WithCreateBatchFunc( func(ctx context.Context, initialBalance *big.Int, depth uint8, immutable bool, label string) ([]byte, error) { id := postagetesting.MustNewID() b := &postage.Batch{ ID: id, Owner: overlayEthAddress.Bytes(), Value: big.NewInt(0), Depth: depth, Immutable: immutable, } totalAmount := big.NewInt(0).Mul(initialBalance, big.NewInt(int64(1<