|
| 1 | +package main |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "math/rand" |
| 6 | + "sort" |
| 7 | + "strings" |
| 8 | + |
| 9 | + "gorm.io/gorm" |
| 10 | + |
| 11 | + "github.com/scroll-tech/da-codec/encoding" |
| 12 | + "github.com/scroll-tech/go-ethereum/common" |
| 13 | + "github.com/scroll-tech/go-ethereum/log" |
| 14 | + |
| 15 | + "scroll-tech/common/database" |
| 16 | + |
| 17 | + "scroll-tech/rollup/internal/orm" |
| 18 | + "scroll-tech/rollup/internal/utils" |
| 19 | +) |
| 20 | + |
| 21 | +type importRecord struct { |
| 22 | + Chunk []string `json:"chunks"` |
| 23 | + Batch []string `json:"batches"` |
| 24 | + Bundle []string `json:"bundles"` |
| 25 | +} |
| 26 | + |
| 27 | +func randomPickKfromN(n, k int, rng *rand.Rand) []int { |
| 28 | + ret := make([]int, n-1) |
| 29 | + for i := 1; i < n; i++ { |
| 30 | + ret[i-1] = i |
| 31 | + } |
| 32 | + |
| 33 | + rng.Shuffle(len(ret), func(i, j int) { |
| 34 | + ret[i], ret[j] = ret[j], ret[i] |
| 35 | + }) |
| 36 | + |
| 37 | + ret = ret[:k-1] |
| 38 | + sort.Ints(ret) |
| 39 | + |
| 40 | + return ret |
| 41 | +} |
| 42 | + |
| 43 | +func importData(ctx context.Context, beginBlk, endBlk uint64, chkNum, batchNum, bundleNum int, seed int64) (*importRecord, error) { |
| 44 | + |
| 45 | + db, err := database.InitDB(cfg.DBConfig) |
| 46 | + if err != nil { |
| 47 | + return nil, err |
| 48 | + } |
| 49 | + ret := &importRecord{} |
| 50 | + // Create a new random source with the provided seed |
| 51 | + source := rand.NewSource(seed) |
| 52 | + //nolint:all |
| 53 | + rng := rand.New(source) |
| 54 | + |
| 55 | + chkSepIdx := randomPickKfromN(int(endBlk-beginBlk)+1, chkNum, rng) |
| 56 | + chkSep := make([]uint64, len(chkSepIdx)) |
| 57 | + for i, ind := range chkSepIdx { |
| 58 | + chkSep[i] = beginBlk + uint64(ind) |
| 59 | + } |
| 60 | + chkSep = append(chkSep, endBlk+1) |
| 61 | + |
| 62 | + log.Info("separated chunk", "border", chkSep) |
| 63 | + head := beginBlk |
| 64 | + lastMsgHash := common.Hash{} |
| 65 | + |
| 66 | + ormChks := make([]*orm.Chunk, 0, chkNum) |
| 67 | + encChks := make([]*encoding.Chunk, 0, chkNum) |
| 68 | + for _, edBlk := range chkSep { |
| 69 | + ormChk, chk, err := importChunk(ctx, db, head, edBlk-1, lastMsgHash) |
| 70 | + if err != nil { |
| 71 | + return nil, err |
| 72 | + } |
| 73 | + lastMsgHash = chk.PostL1MessageQueueHash |
| 74 | + ormChks = append(ormChks, ormChk) |
| 75 | + encChks = append(encChks, chk) |
| 76 | + head = edBlk |
| 77 | + } |
| 78 | + |
| 79 | + for _, chk := range ormChks { |
| 80 | + ret.Chunk = append(ret.Chunk, chk.Hash) |
| 81 | + } |
| 82 | + |
| 83 | + batchSep := randomPickKfromN(chkNum, batchNum, rng) |
| 84 | + batchSep = append(batchSep, chkNum) |
| 85 | + log.Info("separated batch", "border", batchSep) |
| 86 | + |
| 87 | + headChk := int(0) |
| 88 | + batches := make([]*orm.Batch, 0, batchNum) |
| 89 | + var lastBatch *orm.Batch |
| 90 | + for _, endChk := range batchSep { |
| 91 | + batch, err := importBatch(ctx, db, ormChks[headChk:endChk], encChks[headChk:endChk], lastBatch) |
| 92 | + if err != nil { |
| 93 | + return nil, err |
| 94 | + } |
| 95 | + lastBatch = batch |
| 96 | + batches = append(batches, batch) |
| 97 | + headChk = endChk |
| 98 | + } |
| 99 | + |
| 100 | + for _, batch := range batches { |
| 101 | + ret.Batch = append(ret.Batch, batch.Hash) |
| 102 | + } |
| 103 | + |
| 104 | + bundleSep := randomPickKfromN(batchNum, bundleNum, rng) |
| 105 | + bundleSep = append(bundleSep, batchNum) |
| 106 | + log.Info("separated bundle", "border", bundleSep) |
| 107 | + |
| 108 | + headBatch := int(0) |
| 109 | + for _, endBatch := range bundleSep { |
| 110 | + hash, err := importBundle(ctx, db, batches[headBatch:endBatch]) |
| 111 | + if err != nil { |
| 112 | + return nil, err |
| 113 | + } |
| 114 | + ret.Bundle = append(ret.Bundle, hash) |
| 115 | + headBatch = endBatch |
| 116 | + } |
| 117 | + |
| 118 | + return ret, nil |
| 119 | +} |
| 120 | + |
| 121 | +func importChunk(ctx context.Context, db *gorm.DB, beginBlk, endBlk uint64, prevMsgQueueHash common.Hash) (*orm.Chunk, *encoding.Chunk, error) { |
| 122 | + nblk := int(endBlk-beginBlk) + 1 |
| 123 | + blockOrm := orm.NewL2Block(db) |
| 124 | + |
| 125 | + blks, err := blockOrm.GetL2BlocksGEHeight(ctx, beginBlk, nblk) |
| 126 | + |
| 127 | + if err != nil { |
| 128 | + return nil, nil, err |
| 129 | + } |
| 130 | + |
| 131 | + postHash, err := encoding.MessageQueueV2ApplyL1MessagesFromBlocks(prevMsgQueueHash, blks) |
| 132 | + if err != nil { |
| 133 | + return nil, nil, err |
| 134 | + } |
| 135 | + |
| 136 | + theChunk := &encoding.Chunk{ |
| 137 | + Blocks: blks, |
| 138 | + PrevL1MessageQueueHash: prevMsgQueueHash, |
| 139 | + PostL1MessageQueueHash: postHash, |
| 140 | + } |
| 141 | + chunkOrm := orm.NewChunk(db) |
| 142 | + |
| 143 | + dbChk, err := chunkOrm.InsertChunk(ctx, theChunk, codecCfg, utils.ChunkMetrics{}) |
| 144 | + if err != nil { |
| 145 | + return nil, nil, err |
| 146 | + } |
| 147 | + err = blockOrm.UpdateChunkHashInRange(ctx, beginBlk, endBlk, dbChk.Hash) |
| 148 | + if err != nil { |
| 149 | + return nil, nil, err |
| 150 | + } |
| 151 | + log.Info("insert chunk", "From", beginBlk, "To", endBlk, "hash", dbChk.Hash) |
| 152 | + return dbChk, theChunk, nil |
| 153 | +} |
| 154 | + |
| 155 | +func importBatch(ctx context.Context, db *gorm.DB, chks []*orm.Chunk, encChks []*encoding.Chunk, last *orm.Batch) (*orm.Batch, error) { |
| 156 | + |
| 157 | + batchOrm := orm.NewBatch(db) |
| 158 | + if last == nil { |
| 159 | + var err error |
| 160 | + last, err = batchOrm.GetLatestBatch(ctx) |
| 161 | + if err != nil && !strings.Contains(err.Error(), "record not found") { |
| 162 | + return nil, err |
| 163 | + } else if last != nil { |
| 164 | + log.Info("start from last batch", "index", last.Index) |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + index := uint64(0) |
| 169 | + var parentHash common.Hash |
| 170 | + if last != nil { |
| 171 | + index = last.Index + 1 |
| 172 | + parentHash = common.HexToHash(last.Hash) |
| 173 | + } |
| 174 | + |
| 175 | + var blks []*encoding.Block |
| 176 | + for _, chk := range encChks { |
| 177 | + blks = append(blks, chk.Blocks...) |
| 178 | + } |
| 179 | + |
| 180 | + batch := &encoding.Batch{ |
| 181 | + Index: index, |
| 182 | + TotalL1MessagePoppedBefore: chks[0].TotalL1MessagesPoppedBefore, |
| 183 | + ParentBatchHash: parentHash, |
| 184 | + Chunks: encChks, |
| 185 | + Blocks: blks, |
| 186 | + } |
| 187 | + |
| 188 | + dbBatch, err := batchOrm.InsertBatch(ctx, batch, codecCfg, utils.BatchMetrics{}) |
| 189 | + if err != nil { |
| 190 | + return nil, err |
| 191 | + } |
| 192 | + err = orm.NewChunk(db).UpdateBatchHashInRange(ctx, chks[0].Index, chks[len(chks)-1].Index, dbBatch.Hash) |
| 193 | + if err != nil { |
| 194 | + return nil, err |
| 195 | + } |
| 196 | + |
| 197 | + log.Info("insert batch", "index", index) |
| 198 | + return dbBatch, nil |
| 199 | +} |
| 200 | + |
| 201 | +func importBundle(ctx context.Context, db *gorm.DB, batches []*orm.Batch) (string, error) { |
| 202 | + |
| 203 | + bundleOrm := orm.NewBundle(db) |
| 204 | + bundle, err := bundleOrm.InsertBundle(ctx, batches, codecCfg) |
| 205 | + if err != nil { |
| 206 | + return "", err |
| 207 | + } |
| 208 | + err = orm.NewBatch(db).UpdateBundleHashInRange(ctx, batches[0].Index, batches[len(batches)-1].Index, bundle.Hash) |
| 209 | + if err != nil { |
| 210 | + return "", err |
| 211 | + } |
| 212 | + |
| 213 | + log.Info("insert bundle", "hash", bundle.Hash) |
| 214 | + return bundle.Hash, nil |
| 215 | +} |
0 commit comments