github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/utils/cmd.go (about)

     1  package utils
     2  
     3  import (
     4  	"compress/gzip"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"os/signal"
     9  	"runtime"
    10  	"strings"
    11  	"syscall"
    12  
    13  	"github.com/neatio-net/neatio/chain/consensus"
    14  	neatptc "github.com/neatio-net/neatio/neatptc"
    15  	"gopkg.in/urfave/cli.v1"
    16  
    17  	"github.com/neatio-net/neatio/chain/core"
    18  	"github.com/neatio-net/neatio/chain/core/rawdb"
    19  	"github.com/neatio-net/neatio/chain/core/types"
    20  	"github.com/neatio-net/neatio/chain/log"
    21  	"github.com/neatio-net/neatio/neatdb"
    22  	"github.com/neatio-net/neatio/network/node"
    23  	"github.com/neatio-net/neatio/utilities/common"
    24  	"github.com/neatio-net/neatio/utilities/crypto"
    25  	"github.com/neatio-net/neatio/utilities/rlp"
    26  )
    27  
    28  const (
    29  	importBatchSize = 2500
    30  )
    31  
    32  func Fatalf(format string, args ...interface{}) {
    33  	w := io.MultiWriter(os.Stdout, os.Stderr)
    34  	if runtime.GOOS == "windows" {
    35  
    36  		w = os.Stdout
    37  	} else {
    38  		outf, _ := os.Stdout.Stat()
    39  		errf, _ := os.Stderr.Stat()
    40  		if outf != nil && errf != nil && os.SameFile(outf, errf) {
    41  			w = os.Stderr
    42  		}
    43  	}
    44  	fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
    45  	os.Exit(1)
    46  }
    47  
    48  func StartNode(ctx *cli.Context, stack *node.Node) error {
    49  	if err := stack.Start1(); err != nil {
    50  		Fatalf("Error starting protocol stack: %v", err)
    51  	}
    52  
    53  	mining := false
    54  	var neatio *neatptc.NeatIO
    55  	if err := stack.Service(&neatio); err == nil {
    56  		if neatcon, ok := neatio.Engine().(consensus.NeatCon); ok {
    57  			mining = neatcon.ShouldStart()
    58  			if mining {
    59  				stack.GetLogger().Info("NeatCon Consensus Engine will be start shortly")
    60  			}
    61  		}
    62  	}
    63  
    64  	if mining || ctx.GlobalBool(DeveloperFlag.Name) {
    65  		stack.GetLogger().Info("Mine will be start shortly")
    66  
    67  		var neatio *neatptc.NeatIO
    68  		if err := stack.Service(&neatio); err != nil {
    69  			Fatalf("Neatio Blockchain service not running: %v", err)
    70  		}
    71  
    72  		if threads := ctx.GlobalInt(MinerThreadsFlag.Name); threads > 0 {
    73  			type threaded interface {
    74  				SetThreads(threads int)
    75  			}
    76  			if th, ok := neatio.Engine().(threaded); ok {
    77  				th.SetThreads(threads)
    78  			}
    79  		}
    80  
    81  		neatio.TxPool().SetGasPrice(GlobalBig(ctx, MinerGasPriceFlag.Name))
    82  		if err := neatio.StartMining(true); err != nil {
    83  			Fatalf("Failed to start mining: %v", err)
    84  		}
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func ImportChain(chain *core.BlockChain, fn string) error {
    91  
    92  	interrupt := make(chan os.Signal, 1)
    93  	stop := make(chan struct{})
    94  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
    95  	defer signal.Stop(interrupt)
    96  	defer close(interrupt)
    97  	go func() {
    98  		if _, ok := <-interrupt; ok {
    99  			log.Info("Interrupted during import, stopping at next batch")
   100  		}
   101  		close(stop)
   102  	}()
   103  	checkInterrupt := func() bool {
   104  		select {
   105  		case <-stop:
   106  			return true
   107  		default:
   108  			return false
   109  		}
   110  	}
   111  
   112  	log.Info("Importing blockchain", "file", fn)
   113  	fh, err := os.Open(fn)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	defer fh.Close()
   118  
   119  	var reader io.Reader = fh
   120  	if strings.HasSuffix(fn, ".gz") {
   121  		if reader, err = gzip.NewReader(reader); err != nil {
   122  			return err
   123  		}
   124  	}
   125  	stream := rlp.NewStream(reader, 0)
   126  
   127  	blocks := make(types.Blocks, importBatchSize)
   128  	n := 0
   129  	for batch := 0; ; batch++ {
   130  
   131  		if checkInterrupt() {
   132  			return fmt.Errorf("interrupted")
   133  		}
   134  		i := 0
   135  		for ; i < importBatchSize; i++ {
   136  			var b types.Block
   137  			if err := stream.Decode(&b); err == io.EOF {
   138  				break
   139  			} else if err != nil {
   140  				return fmt.Errorf("at block %d: %v", n, err)
   141  			}
   142  
   143  			if b.NumberU64() == 0 {
   144  				i--
   145  				continue
   146  			}
   147  			blocks[i] = &b
   148  			n++
   149  		}
   150  		if i == 0 {
   151  			break
   152  		}
   153  
   154  		if checkInterrupt() {
   155  			return fmt.Errorf("interrupted")
   156  		}
   157  		missing := missingBlocks(chain, blocks[:i])
   158  		if len(missing) == 0 {
   159  			log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash())
   160  			continue
   161  		}
   162  		if _, err := chain.InsertChain(missing); err != nil {
   163  			return fmt.Errorf("invalid block %d: %v", n, err)
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block {
   170  	head := chain.CurrentBlock()
   171  	for i, block := range blocks {
   172  
   173  		if head.NumberU64() > block.NumberU64() {
   174  			if !chain.HasBlock(block.Hash(), block.NumberU64()) {
   175  				return blocks[i:]
   176  			}
   177  			continue
   178  		}
   179  
   180  		if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
   181  			return blocks[i:]
   182  		}
   183  	}
   184  	return nil
   185  }
   186  
   187  func ExportChain(blockchain *core.BlockChain, fn string) error {
   188  	log.Info("Exporting blockchain", "file", fn)
   189  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   190  	if err != nil {
   191  		return err
   192  	}
   193  	defer fh.Close()
   194  
   195  	var writer io.Writer = fh
   196  	if strings.HasSuffix(fn, ".gz") {
   197  		writer = gzip.NewWriter(writer)
   198  		defer writer.(*gzip.Writer).Close()
   199  	}
   200  
   201  	if err := blockchain.Export(writer); err != nil {
   202  		return err
   203  	}
   204  	log.Info("Exported blockchain", "file", fn)
   205  
   206  	return nil
   207  }
   208  
   209  func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
   210  	log.Info("Exporting blockchain", "file", fn)
   211  
   212  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
   213  	if err != nil {
   214  		return err
   215  	}
   216  	defer fh.Close()
   217  
   218  	var writer io.Writer = fh
   219  	if strings.HasSuffix(fn, ".gz") {
   220  		writer = gzip.NewWriter(writer)
   221  		defer writer.(*gzip.Writer).Close()
   222  	}
   223  
   224  	if err := blockchain.ExportN(writer, first, last); err != nil {
   225  		return err
   226  	}
   227  	log.Info("Exported blockchain to", "file", fn)
   228  	return nil
   229  }
   230  
   231  func ImportPreimages(db neatdb.Database, fn string) error {
   232  	log.Info("Importing preimages", "file", fn)
   233  
   234  	fh, err := os.Open(fn)
   235  	if err != nil {
   236  		return err
   237  	}
   238  	defer fh.Close()
   239  
   240  	var reader io.Reader = fh
   241  	if strings.HasSuffix(fn, ".gz") {
   242  		if reader, err = gzip.NewReader(reader); err != nil {
   243  			return err
   244  		}
   245  	}
   246  	stream := rlp.NewStream(reader, 0)
   247  
   248  	preimages := make(map[common.Hash][]byte)
   249  
   250  	for {
   251  
   252  		var blob []byte
   253  
   254  		if err := stream.Decode(&blob); err != nil {
   255  			if err == io.EOF {
   256  				break
   257  			}
   258  			return err
   259  		}
   260  
   261  		preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
   262  		if len(preimages) > 1024 {
   263  			rawdb.WritePreimages(db, preimages)
   264  			preimages = make(map[common.Hash][]byte)
   265  		}
   266  	}
   267  
   268  	if len(preimages) > 0 {
   269  		rawdb.WritePreimages(db, preimages)
   270  	}
   271  	return nil
   272  }
   273  
   274  func ExportPreimages(db neatdb.Database, fn string) error {
   275  	log.Info("Exporting preimages", "file", fn)
   276  
   277  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	defer fh.Close()
   282  
   283  	var writer io.Writer = fh
   284  	if strings.HasSuffix(fn, ".gz") {
   285  		writer = gzip.NewWriter(writer)
   286  		defer writer.(*gzip.Writer).Close()
   287  	}
   288  
   289  	it := db.NewIteratorWithPrefix([]byte("secure-key-"))
   290  	defer it.Release()
   291  
   292  	for it.Next() {
   293  		if err := rlp.Encode(writer, it.Value()); err != nil {
   294  			return err
   295  		}
   296  	}
   297  	log.Info("Exported preimages", "file", fn)
   298  	return nil
   299  }