github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/cmd/u2u/launcher/export.go (about)

     1  package launcher
     2  
     3  import (
     4  	"compress/gzip"
     5  	"io"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"gopkg.in/urfave/cli.v1"
    12  
    13  	"github.com/status-im/keycard-go/hexutils"
    14  	"github.com/syndtr/goleveldb/leveldb/opt"
    15  
    16  	"github.com/unicornultrafoundation/go-u2u/cmd/utils"
    17  	"github.com/unicornultrafoundation/go-u2u/common"
    18  	"github.com/unicornultrafoundation/go-u2u/log"
    19  	"github.com/unicornultrafoundation/go-u2u/rlp"
    20  
    21  	"github.com/unicornultrafoundation/go-helios/hash"
    22  	"github.com/unicornultrafoundation/go-helios/native/idx"
    23  	"github.com/unicornultrafoundation/go-helios/u2udb/batched"
    24  	"github.com/unicornultrafoundation/go-helios/u2udb/pebble"
    25  
    26  	"github.com/unicornultrafoundation/go-u2u/gossip"
    27  	"github.com/unicornultrafoundation/go-u2u/utils/dbutil/autocompact"
    28  )
    29  
    30  var (
    31  	eventsFileHeader  = hexutils.HexToBytes("7e995678")
    32  	eventsFileVersion = hexutils.HexToBytes("00010001")
    33  )
    34  
    35  // statsReportLimit is the time limit during import and export after which we
    36  // always print out progress. This avoids the user wondering what's going on.
    37  const statsReportLimit = 8 * time.Second
    38  
    39  func exportEvents(ctx *cli.Context) error {
    40  	if len(ctx.Args()) < 1 {
    41  		utils.Fatalf("This command requires an argument.")
    42  	}
    43  
    44  	cfg := makeAllConfigs(ctx)
    45  
    46  	rawDbs := makeDirectDBsProducer(cfg)
    47  	gdb := makeGossipStore(rawDbs, cfg)
    48  	defer gdb.Close()
    49  
    50  	fn := ctx.Args().First()
    51  
    52  	// Open the file handle and potentially wrap with a gzip stream
    53  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer fh.Close()
    58  
    59  	var writer io.Writer = fh
    60  	if strings.HasSuffix(fn, ".gz") {
    61  		writer = gzip.NewWriter(writer)
    62  		defer writer.(*gzip.Writer).Close()
    63  	}
    64  
    65  	from := idx.Epoch(1)
    66  	if len(ctx.Args()) > 1 {
    67  		n, err := strconv.ParseUint(ctx.Args().Get(1), 10, 32)
    68  		if err != nil {
    69  			return err
    70  		}
    71  		from = idx.Epoch(n)
    72  	}
    73  	to := idx.Epoch(0)
    74  	if len(ctx.Args()) > 2 {
    75  		n, err := strconv.ParseUint(ctx.Args().Get(2), 10, 32)
    76  		if err != nil {
    77  			return err
    78  		}
    79  		to = idx.Epoch(n)
    80  	}
    81  
    82  	log.Info("Exporting events to file", "file", fn)
    83  	// Write header and version
    84  	_, err = writer.Write(append(eventsFileHeader, eventsFileVersion...))
    85  	if err != nil {
    86  		return err
    87  	}
    88  	err = exportTo(writer, gdb, from, to)
    89  	if err != nil {
    90  		utils.Fatalf("Export error: %v\n", err)
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  // exportTo writer the active chain.
    97  func exportTo(w io.Writer, gdb *gossip.Store, from, to idx.Epoch) (err error) {
    98  	start, reported := time.Now(), time.Time{}
    99  
   100  	var (
   101  		counter int
   102  		last    hash.Event
   103  	)
   104  	gdb.ForEachEventRLP(from.Bytes(), func(id hash.Event, event rlp.RawValue) bool {
   105  		if to >= from && id.Epoch() > to {
   106  			return false
   107  		}
   108  		counter++
   109  		_, err = w.Write(event)
   110  		if err != nil {
   111  			return false
   112  		}
   113  		last = id
   114  		if counter%100 == 1 && time.Since(reported) >= statsReportLimit {
   115  			log.Info("Exporting events", "last", last.String(), "exported", counter, "elapsed", common.PrettyDuration(time.Since(start)))
   116  			reported = time.Now()
   117  		}
   118  		return true
   119  	})
   120  	log.Info("Exported events", "last", last.String(), "exported", counter, "elapsed", common.PrettyDuration(time.Since(start)))
   121  
   122  	return
   123  }
   124  
   125  func exportEvmKeys(ctx *cli.Context) error {
   126  	if len(ctx.Args()) < 1 {
   127  		utils.Fatalf("This command requires an argument.")
   128  	}
   129  
   130  	cfg := makeAllConfigs(ctx)
   131  
   132  	rawDbs := makeDirectDBsProducer(cfg)
   133  	gdb := makeGossipStore(rawDbs, cfg)
   134  	defer gdb.Close()
   135  
   136  	fn := ctx.Args().First()
   137  
   138  	keysDB_, err := pebble.New(fn, 1024*opt.MiB, utils.MakeDatabaseHandles()/2, nil, nil)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	keysDB := batched.Wrap(autocompact.Wrap2M(keysDB_, opt.GiB, 16*opt.GiB, true, "evm-keys"))
   143  	defer keysDB.Close()
   144  
   145  	it := gdb.EvmStore().EvmDb.NewIterator(nil, nil)
   146  	// iterate only over MPT data
   147  	it = mptAndPreimageIterator{it}
   148  	defer it.Release()
   149  
   150  	log.Info("Exporting EVM keys", "dir", fn)
   151  	for it.Next() {
   152  		if err := keysDB.Put(it.Key(), []byte{0}); err != nil {
   153  			return err
   154  		}
   155  	}
   156  	log.Info("Exported EVM keys", "dir", fn)
   157  	return nil
   158  }