github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/cmd/u2u/launcher/import.go (about) 1 package launcher 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "errors" 7 "fmt" 8 "io" 9 "math" 10 "os" 11 "os/signal" 12 "strings" 13 "syscall" 14 "time" 15 16 "github.com/status-im/keycard-go/hexutils" 17 "github.com/unicornultrafoundation/go-helios/hash" 18 "github.com/unicornultrafoundation/go-helios/native/idx" 19 "github.com/unicornultrafoundation/go-u2u/cmd/utils" 20 "github.com/unicornultrafoundation/go-u2u/common" 21 "github.com/unicornultrafoundation/go-u2u/log" 22 "github.com/unicornultrafoundation/go-u2u/rlp" 23 "gopkg.in/urfave/cli.v1" 24 25 "github.com/unicornultrafoundation/go-u2u/gossip" 26 "github.com/unicornultrafoundation/go-u2u/gossip/emitter" 27 "github.com/unicornultrafoundation/go-u2u/native" 28 "github.com/unicornultrafoundation/go-u2u/u2u/genesisstore" 29 "github.com/unicornultrafoundation/go-u2u/utils/ioread" 30 ) 31 32 func importEvm(ctx *cli.Context) error { 33 if len(ctx.Args()) < 1 { 34 utils.Fatalf("This command requires an argument.") 35 } 36 37 cfg := makeAllConfigs(ctx) 38 39 rawDbs := makeDirectDBsProducer(cfg) 40 gdb := makeGossipStore(rawDbs, cfg) 41 defer gdb.Close() 42 43 for _, fn := range ctx.Args() { 44 log.Info("Importing EVM storage from file", "file", fn) 45 if err := importEvmFile(fn, gdb); err != nil { 46 log.Error("Import error", "file", fn, "err", err) 47 return err 48 } 49 log.Info("Imported EVM storage from file", "file", fn) 50 } 51 52 return nil 53 } 54 55 func importEvmFile(fn string, gdb *gossip.Store) error { 56 // Open the file handle and potentially unwrap the gzip stream 57 fh, err := os.Open(fn) 58 if err != nil { 59 return err 60 } 61 defer fh.Close() 62 63 var reader io.Reader = fh 64 if strings.HasSuffix(fn, ".gz") { 65 if reader, err = gzip.NewReader(reader); err != nil { 66 return err 67 } 68 defer reader.(*gzip.Reader).Close() 69 } 70 71 return gdb.EvmStore().ImportEvm(reader) 72 } 73 74 func importEvents(ctx *cli.Context) error { 75 if len(ctx.Args()) < 1 { 76 utils.Fatalf("This command requires an argument.") 77 } 78 79 // avoid P2P interaction, API calls and events emitting 80 genesisStore := mayGetGenesisStore(ctx) 81 cfg := makeAllConfigs(ctx) 82 cfg.U2U.Protocol.EventsSemaphoreLimit.Size = math.MaxUint32 83 cfg.U2U.Protocol.EventsSemaphoreLimit.Num = math.MaxUint32 84 cfg.Emitter.Validator = emitter.ValidatorConfig{} 85 cfg.TxPool.Journal = "" 86 cfg.Node.IPCPath = "" 87 cfg.Node.HTTPHost = "" 88 cfg.Node.WSHost = "" 89 cfg.Node.NoUSB = true 90 cfg.Node.P2P.ListenAddr = "" 91 cfg.Node.P2P.NoDiscovery = true 92 cfg.Node.P2P.BootstrapNodes = nil 93 cfg.Node.P2P.DiscoveryV5 = false 94 cfg.Node.P2P.BootstrapNodesV5 = nil 95 cfg.Node.P2P.StaticNodes = nil 96 cfg.Node.P2P.TrustedNodes = nil 97 98 err := importEventsToNode(ctx, cfg, genesisStore, ctx.Args()...) 99 if err != nil { 100 return err 101 } 102 103 return nil 104 } 105 106 func importEventsToNode(ctx *cli.Context, cfg *config, genesisStore *genesisstore.Store, args ...string) error { 107 node, svc, nodeClose := makeNode(ctx, cfg, genesisStore) 108 defer nodeClose() 109 startNode(ctx, node) 110 111 for _, fn := range args { 112 log.Info("Importing events from file", "file", fn) 113 if err := importEventsFile(svc, fn); err != nil { 114 log.Error("Import error", "file", fn, "err", err) 115 return err 116 } 117 } 118 return nil 119 } 120 121 func checkEventsFileHeader(reader io.Reader) error { 122 headerAndVersion := make([]byte, len(eventsFileHeader)+len(eventsFileVersion)) 123 err := ioread.ReadAll(reader, headerAndVersion) 124 if err != nil { 125 return err 126 } 127 if bytes.Compare(headerAndVersion[:len(eventsFileHeader)], eventsFileHeader) != 0 { 128 return errors.New("expected an events file, mismatched file header") 129 } 130 if bytes.Compare(headerAndVersion[len(eventsFileHeader):], eventsFileVersion) != 0 { 131 got := hexutils.BytesToHex(headerAndVersion[len(eventsFileHeader):]) 132 expected := hexutils.BytesToHex(eventsFileVersion) 133 return errors.New(fmt.Sprintf("wrong version of events file, got=%s, expected=%s", got, expected)) 134 } 135 return nil 136 } 137 138 func importEventsFile(srv *gossip.Service, fn string) error { 139 // Watch for Ctrl-C while the import is running. 140 // If a signal is received, the import will stop. 141 interrupt := make(chan os.Signal, 1) 142 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) 143 defer signal.Stop(interrupt) 144 145 // wait until snapshot generation is complete 146 for srv.EvmSnapshotGeneration() { 147 select { 148 case <-interrupt: 149 return fmt.Errorf("interrupted") 150 case <-time.After(100 * time.Millisecond): 151 continue 152 } 153 } 154 155 // Open the file handle and potentially unwrap the gzip stream 156 fh, err := os.Open(fn) 157 if err != nil { 158 return err 159 } 160 defer fh.Close() 161 162 var reader io.Reader = fh 163 if strings.HasSuffix(fn, ".gz") { 164 if reader, err = gzip.NewReader(reader); err != nil { 165 return err 166 } 167 defer reader.(*gzip.Reader).Close() 168 } 169 170 // Check file version and header 171 if err := checkEventsFileHeader(reader); err != nil { 172 return err 173 } 174 175 stream := rlp.NewStream(reader, 0) 176 177 start := time.Now() 178 last := hash.Event{} 179 180 batch := make(native.EventPayloads, 0, 8*1024) 181 batchSize := 0 182 maxBatchSize := 8 * 1024 * 1024 183 epoch := idx.Epoch(0) 184 txs := 0 185 events := 0 186 187 processBatch := func() error { 188 if batch.Len() == 0 { 189 return nil 190 } 191 done := make(chan struct{}) 192 err := srv.DagProcessor().Enqueue("", batch.Bases(), true, nil, func() { 193 done <- struct{}{} 194 }) 195 if err != nil { 196 return err 197 } 198 <-done 199 last = batch[batch.Len()-1].ID() 200 batch = batch[:0] 201 batchSize = 0 202 return nil 203 } 204 205 for { 206 select { 207 case <-interrupt: 208 return fmt.Errorf("interrupted") 209 default: 210 } 211 e := new(native.EventPayload) 212 err = stream.Decode(e) 213 if err == io.EOF { 214 err = processBatch() 215 if err != nil { 216 return err 217 } 218 break 219 } 220 if err != nil { 221 return err 222 } 223 if e.Epoch() != epoch || batchSize >= maxBatchSize { 224 err = processBatch() 225 if err != nil { 226 return err 227 } 228 } 229 epoch = e.Epoch() 230 batch = append(batch, e) 231 batchSize += 1024 + e.Size() 232 txs += e.Txs().Len() 233 events++ 234 } 235 srv.WaitBlockEnd() 236 log.Info("Events import is finished", "file", fn, "last", last.String(), "imported", events, "txs", txs, "elapsed", common.PrettyDuration(time.Since(start))) 237 238 return nil 239 }