diff --git a/tools/datastreamer/README.md b/tools/datastreamer/README.md index d80cf689c7..c53593fe0d 100644 --- a/tools/datastreamer/README.md +++ b/tools/datastreamer/README.md @@ -93,59 +93,73 @@ Almost all the decode options can work online, connecting to a node serving the Note: `Version` and `ChainID` fields from the Offline section of the config file are used during generation, so make sure they both are correct. Current Value for Version should be `3`. -### Get contents of Batch 1 from the local files +### Get contents of Batch 201 from the local files -`make decode-batch-offline 1` +`make decode-batch-offline 201` ``` -Entry Type......: Batch Start -Entry Number....: 6 -Batch Number....: 1 -Batch Type......: BATCH_TYPE_INJECTED -Fork ID.........: 9 -Chain ID........: 6969 -Entry Type......: BookMark -Entry Number....: 7 -Type............: 2 (BOOKMARK_TYPE_L2_BLOCK) -Value...........: 1 -Entry Type......: L2 Block -Entry Number....: 8 -L2 Block Number.: 1 -Batch Number....: 1 -Timestamp.......: 1714380108 (2024-04-29 08:41:48 +0000 UTC) -Delta Timestamp.: 1714380108 -Min. Timestamp..: 0 -L1 Block Hash...: 0xdeaef97f8a5c6f056d08e162073d720c035a25adcaa2cd868124543ea54fb185 -L1 InfoTree Idx.: 0 -Block Hash......: 0xeeb2b1e810770dc1dcdd71a7ffa2a81ae77642d1e3c389919464100b3f70e366 -State Root......: 0xada6af5a8bf491712d5ba14c67283a7b516245cd571151c5ade13f82532a398d -Global Exit Root: 0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5 -Coinbase........: 0x5BD65BF6e084ECC10565EED59b838E82aBc28083 -Block Gas Limit.: 0 -Block Info Root.: 0x5dfdd92c4436374df99c4532ca7b8b1732faa10e9a6e31e0868bd4bfb6e8303d -Entry Type......: L2 Transaction -Entry Number....: 9 -L2 Block Number.: 1 -Index...........: 0 -Is Valid........: true -Data............: 0xf9010f80808401c9c38094ca127484cda2b723c4c03558b94749184d3cfa9880b8e4f811bff7000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40d5f56745a118d0906a34e69aec8c0db1cb8fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000001b8505ca1ab1e0845ca1ab1e -Effec. Gas Price: 255 -IM State Root...: 0xeb6b784c61931c8d188ce19298799000615de174e17850ae53feb496b4a5a6ca -Sender..........: 0x2CfbeDbE634712c0Cec2Cd929DcB8c23B0038F2A -Nonce...........: 0 -Entry Type......: Batch End -Entry Number....: 10 -Batch Number....: 1 -State Root......: 0xada6af5a8bf491712d5ba14c67283a7b516245cd571151c5ade13f82532a398d -Local Exit Root.: 0x0000000000000000000000000000000000000000000000000000000000000000 +Entry Type···············: Batch Start +Batch Number·············: 201 +Batch Type···············: BATCH_TYPE_REGULAR +Chain ID ················: 2440 +Entry Number·············: 17575 +Entry Type···············: Batch Start +Fork ID··················: 7 +Entry Type···············: BookMark +Entry Number·············: 17576 +Entry Type···············: BookMark +Type·····················: 2 (BOOKMARK_TYPE_L2_BLOCK) +Value····················: 4259 +Entry Type···············: L2 Block +Batch Number·············: 201 +Block Gas Limit··········: 0 +Block Hash···············: 0xbd2fde31c1ba2bb17f6b1edec5e7d3576ae645b4b8095b74152ad28ba4a8bab4 +Block Info Root··········: 0x4e63bbbe4d34e6b3d8d531a2da5cffb4e3877414ecfe4dde24d2afaf3fd0d7a0 +Coinbase·················: 0x9aeCf44E36f20DC407d1A580630c9a2419912dcB +Delta Timestamp··········: 3 +Entry Number·············: 17577 +Entry Type···············: L2 Block +Global Exit Root·········: 0x0000000000000000000000000000000000000000000000000000000000000000 +L1 Block Hash············: 0x0000000000000000000000000000000000000000000000000000000000000000 +L1 InfoTree Idx··········: 0 +L2 Block Number··········: 4259 +Min. Timestamp···········: 0 +State Root···············: 0x0b649d223f59634d612b0b101ada69310f2f1485e7f38d8a392642229a57863b +Timestamp················: 1706276938 (2024-01-26 08:48:58 -0500 EST) +Entry Type···············: BookMark +Entry Number·············: 17579 +Entry Type···············: BookMark +Type·····················: 2 (BOOKMARK_TYPE_L2_BLOCK) +Value····················: 4260 +Entry Type···············: BookMark +Entry Number·············: 17582 +Entry Type···············: BookMark +Type·····················: 2 (BOOKMARK_TYPE_L2_BLOCK) +Value····················: 4261 +Entry Type···············: BookMark +Entry Number·············: 17586 +Entry Type···············: BookMark +Type·····················: 1 (BOOKMARK_TYPE_BATCH) +Value····················: 202 +Entry Type···············: BookMark +Entry Number·············: 17591 +Entry Type···············: BookMark +Type·····················: 2 (BOOKMARK_TYPE_L2_BLOCK) +Value····················: 4263 +Entry Type···············: Batch End +Batch Number·············: 202 +Entry Number·············: 17597 +Entry Type···············: Batch End +Local Exit Root··········: 0x4c907345c62b48529ce718f3a32e8be63a3ae02831386a638419c6cbe6606558 +State Root···············: 0x7d2fbae3341b01aa6acb39e113fb98797f3e3da0cddb80b333ae5f8dcb916c7b ``` ### Get BatchL2Data from Batch 2 in the Data Stream -`make decode-batchl2data 1` +`make decode-batchl2data 201` ``` -BatchL2Data.....: 0x0b662f5d4c00000000f9010380808401c9c38094ca127484cda2b723c4c03558b94749184d3cfa9880b8e4f811bff7000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40d5f56745a118d0906a34e69aec8c0db1cb8fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005ca1ab1e0000000000000000000000000000000000000000000000000000000005ca1ab1e1bff +BatchL2Data.....: 0x0b00000003000000000b00000003000000000b0000000300000000 ``` ### Get content of L2Block 1 from an online Data Stream @@ -153,29 +167,50 @@ BatchL2Data.....: 0x0b662f5d4c00000000f9010380808401c9c38094ca127484cda2b723c4c0 `make decode-l2block 1` ``` -Entry Type......: L2 Block -Entry Number....: 8 -L2 Block Number.: 1 -Batch Number....: 1 -Timestamp.......: 1714380108 (2024-04-29 08:41:48 +0000 UTC) -Delta Timestamp.: 1714380108 -Min. Timestamp..: 0 -L1 Block Hash...: 0xdeaef97f8a5c6f056d08e162073d720c035a25adcaa2cd868124543ea54fb185 -L1 InfoTree Idx.: 0 -Block Hash......: 0xeeb2b1e810770dc1dcdd71a7ffa2a81ae77642d1e3c389919464100b3f70e366 -State Root......: 0xada6af5a8bf491712d5ba14c67283a7b516245cd571151c5ade13f82532a398d -Global Exit Root: 0xad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5 -Coinbase........: 0x5BD65BF6e084ECC10565EED59b838E82aBc28083 -Block Gas Limit.: 0 -Block Info Root.: 0x5dfdd92c4436374df99c4532ca7b8b1732faa10e9a6e31e0868bd4bfb6e8303d -Entry Type......: L2 Transaction -Entry Number....: 9 -L2 Block Number.: 1 -Index...........: 0 -Is Valid........: true -Data............: 0xf9010f80808401c9c38094ca127484cda2b723c4c03558b94749184d3cfa9880b8e4f811bff7000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a40d5f56745a118d0906a34e69aec8c0db1cb8fa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000001b8505ca1ab1e0845ca1ab1e -Effec. Gas Price: 255 -IM State Root...: 0x0000000000000000000000000000000000000000000000000000000000000000 -Sender..........: 0x2CfbeDbE634712c0Cec2Cd929DcB8c23B0038F2A -Nonce...........: 0 -``` \ No newline at end of file +Entry Type···············: L2 Block +Batch Number·············: 1 +Block Gas Limit··········: 0 +Block Hash···············: 0x2d19690496337b8f0048d589c4d82820cd46a63f993cca5fc25cd738cce29dad +Block Info Root··········: 0x0000000000000000000000000000000000000000000000000000000000000000 +Coinbase·················: 0x9aeCf44E36f20DC407d1A580630c9a2419912dcB +Delta Timestamp··········: 1701345162 +Entry Number·············: 9 +Entry Type···············: L2 Block +Global Exit Root·········: 0x0000000000000000000000000000000000000000000000000000000000000000 +L1 Block Hash············: 0x0000000000000000000000000000000000000000000000000000000000000000 +L1 InfoTree Idx··········: 0 +L2 Block Number··········: 1 +Min. Timestamp···········: 0 +State Root···············: 0x9333321a6e1253c5c12922b2c1fcb4f9b6fac830d80951f4f08a640cd61dfcc4 +Timestamp················: 1701345162 (2023-11-30 06:52:42 -0500 EST) +Entry Type···············: L2 Transaction +Data·····················: 0xf86a0884025625008252089488cd377500be9906c46073f54901878d1aedc72f870286db33b3c300801ca0e8941bb474e66cc662ce2cf7f52a8b45596e4bebeafd698dc6b10002ff9e04aca048b0b802b0f442fed738ba74d4d53823b3aa60bd9306002486950208b5d8cd7e +Effec. Gas Price·········: 0 +Entry Number·············: 10 +Entry Type···············: L2 Transaction +IM State Root ···········: 0xae431fe8723d233e04045201057e257d046ebf6d4ba93baf0d1203209b4de9ea +Index····················: 0 +Is Valid·················: true +L2 Block Number··········: 1 +Nonce ···················: 8 +Sender···················: 0x229A5bDBb09d8555f9214F7a6784804999BA4E0D +Entry Type···············: L2 Block End +Entry Number·············: 11 +Entry Type···············: L2 Block End +L2 Block Number··········: 1 +``` + +### Get contents of Batch 201 from the local files as a JSON stream + +By default, the make file targets output content in a convenient, human-readable format. The same data can be retrieved as a [newline delimited JSON](https://github.com/ndjson/ndjson-spec) stream by adding the `--json` flag. + +`go run main.go decode-batch --cfg config/tool.config.toml --batch 201 --json` + + +``` +{"Batch Number":"201","Batch Type":"BATCH_TYPE_REGULAR","Chain ID ":"10101","Entry Number":"62682","Entry Type":"Batch Start","Fork ID":"12"} +{"Entry Number":"62683","Entry Type":"BookMark","Type":"2 (BOOKMARK_TYPE_L2_BLOCK)","Value":"426"} +{"Batch Number":"201","Block Gas Limit":"0","Block Hash":"0xbc518d2e5a43f165bb0a9946fe5255a6810e638fd709dcd7065db31e6e5111cd","Block Info Root":"0x229bc3f5ea59c0628cf75a80517e0dcdb2e817177cacdf7ffa27ad05ee37d1f9","Coinbase":"0x5b06837A43bdC3dD9F114558DAf4B26ed49842Ed","Delta Timestamp":"2","Entry Number":"62684","Entry Type":"L2 Block","Global Exit Root":"0x0000000000000000000000000000000000000000000000000000000000000000","L1 Block Hash":"0x0000000000000000000000000000000000000000000000000000000000000000","L1 InfoTree Idx":"0","L2 Block Number":"426","Min. Timestamp":"0","State Root":"0x0d43082ea60965b1bf7bccb0001babf0b486390e4bf13cadb6282aae219ea8f5","Timestamp":"1727205926 (2024-09-24 15:25:26 -0400 EDT)"} +{"Data":"0xf86e82ed86843b9aca0082520894deadbeefdeadbeefdeadbeefdeadbeefdeadbeef87038d7ea4c6800080824f0da09fad01f022fa8675a5eb04a9e062eae1efed7c1e0ccac394bd821cc925b2707ba02494a393b3c6720f1c2da44a92296738724cbdbc0c0449e6b2e1e977626dc761","Effec. Gas Price":"255","Entry Number":"62685","Entry Type":"L2 Transaction","IM State Root ":"0x0000000000000000000000000000000000000000000000000000000000000000","Index":"0","Is Valid":"true","L2 Block Number":"426","Nonce ":"60806","Sender":"0xe34aaf64b29273b7d567fcfc40544c014eee9970"} +{"Data":"0xf86e82ed87843b9aca0082520894deadbeefdeadbeefdeadbeefdeadbeefdeadbeef87038d7ea4c6800080824f0da0b39f4f13d0b68095d45bbae09608d264ba09056d905d95d2fa73a5158fa1c0ffa056c06604a5d400784addd5e044f3f4be4aadbeb3d919b77e11c6867c1d53a289","Effec. Gas Price":"255","Entry Number":"62686","Entry Type":"L2 Transaction","IM State Root ":"0x0000000000000000000000000000000000000000000000000000000000000000","Index":"0","Is Valid":"true","L2 Block Number":"426","Nonce ":"60807","Sender":"0xe34aaf64b29273b7d567fcfc40544c014eee9970"} +``` diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go index 430c684e58..78f7b5542c 100644 --- a/tools/datastreamer/main.go +++ b/tools/datastreamer/main.go @@ -6,6 +6,8 @@ import ( "fmt" "math/big" "os" + "sort" + "strings" "sync" "time" @@ -64,6 +66,12 @@ var ( Usage: "Dump batch to file", Required: false, } + jsonFlag = cli.BoolFlag{ + Name: "json", + Aliases: []string{"j"}, + Usage: "Print data as a JSON stream", + Required: false, + } ) type batch struct { @@ -109,6 +117,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &entryFlag, + &jsonFlag, }, }, { @@ -119,6 +128,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &l2blockFlag, + &jsonFlag, }, }, { @@ -129,6 +139,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &batchFlag, + &jsonFlag, }, }, { @@ -139,6 +150,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &entryFlag, + &jsonFlag, }, }, { @@ -149,6 +161,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &l2blockFlag, + &jsonFlag, }, }, { @@ -159,6 +172,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &batchFlag, + &jsonFlag, }, }, { @@ -169,6 +183,7 @@ func main() { Flags: []cli.Flag{ &configFileFlag, &batchFlag, + &jsonFlag, }, }, { @@ -190,6 +205,7 @@ func main() { &configFileFlag, &batchFlag, &dumpFlag, + &jsonFlag, }, }, { @@ -201,6 +217,7 @@ func main() { &configFileFlag, &batchFlag, &dumpFlag, + &jsonFlag, }, }, } @@ -421,7 +438,8 @@ func decodeEntry(cliCtx *cli.Context) error { os.Exit(1) } - printEntry(entry) + shouldPrintJson := cliCtx.Bool("json") + printEntry(entry, shouldPrintJson) return nil } @@ -463,7 +481,8 @@ func decodeL2Block(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(firstEntry) + shouldPrintJson := cliCtx.Bool("json") + printEntry(firstEntry, shouldPrintJson) secondEntry, err := client.ExecCommandGetEntry(firstEntry.Number + 1) if err != nil { @@ -473,7 +492,7 @@ func decodeL2Block(cliCtx *cli.Context) error { i := uint64(2) //nolint:gomnd for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) { - printEntry(secondEntry) + printEntry(secondEntry, shouldPrintJson) entry, err := client.ExecCommandGetEntry(firstEntry.Number + i) if err != nil { log.Error(err) @@ -489,7 +508,7 @@ func decodeL2Block(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(l2BlockEnd) + printEntry(l2BlockEnd, shouldPrintJson) } return nil @@ -515,8 +534,8 @@ func decodeEntryOffline(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - - printEntry(entry) + shouldPrintJson := cliCtx.Bool("json") + printEntry(entry, shouldPrintJson) return nil } @@ -553,7 +572,8 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(firstEntry) + shouldPrintJson := cliCtx.Bool("json") + printEntry(firstEntry, shouldPrintJson) secondEntry, err := streamServer.GetEntry(firstEntry.Number + 1) if err != nil { @@ -564,7 +584,7 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error { i := uint64(2) //nolint:gomnd for secondEntry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION) { - printEntry(secondEntry) + printEntry(secondEntry, shouldPrintJson) secondEntry, err = streamServer.GetEntry(firstEntry.Number + i) if err != nil { log.Error(err) @@ -579,7 +599,7 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(l2BlockEnd) + printEntry(l2BlockEnd, shouldPrintJson) } return nil @@ -634,6 +654,7 @@ func decodeBatch(cliCtx *cli.Context) error { } batchNumber := cliCtx.Uint64("batch") + shouldPrintJson := cliCtx.Bool("json") bookMark := &datastream.BookMark{ Type: datastream.BookmarkType_BOOKMARK_TYPE_BATCH, @@ -650,7 +671,7 @@ func decodeBatch(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(entry) + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) @@ -659,7 +680,7 @@ func decodeBatch(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(entry) + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) @@ -671,7 +692,7 @@ func decodeBatch(cliCtx *cli.Context) error { os.Exit(1) } - printEntry(entry) + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) if entry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_END) { break @@ -726,7 +747,8 @@ func decodeBatchOffline(cliCtx *cli.Context) error { log.Error(err) os.Exit(1) } - printEntry(entry) + shouldPrintJson := cliCtx.Bool("json") + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) entry, err = streamServer.GetEntry(entry.Number + 1) @@ -736,7 +758,7 @@ func decodeBatchOffline(cliCtx *cli.Context) error { } i := uint64(1) //nolint:gomnd - printEntry(entry) + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) for { entry, err = streamServer.GetEntry(entry.Number + i) @@ -745,7 +767,7 @@ func decodeBatchOffline(cliCtx *cli.Context) error { os.Exit(1) } - printEntry(entry) + printEntry(entry, shouldPrintJson) batchData = append(batchData, entry.Encode()...) if entry.Type == datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_END) { break @@ -912,7 +934,9 @@ func (h *handler) handleReceivedDataStream(entry *datastreamer.FileEntry, client return nil } -func printEntry(entry datastreamer.FileEntry) { +func printEntry(entry datastreamer.FileEntry, shouldPrintJson bool) { + simpleEntry := make(map[string]any) + switch entry.Type { case state.EntryTypeBookMark: bookmark := &datastream.BookMark{} @@ -922,14 +946,10 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "BookMark\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "Type............: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d (%s)\n", bookmark.Type, datastream.BookmarkType_name[int32(bookmark.Type)])) - printColored(color.FgGreen, "Value...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", bookmark.Value)) + simpleEntry["Entry Type"] = "BookMark" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["Type"] = fmt.Sprintf("%d (%s)", bookmark.Type, datastream.BookmarkType_name[int32(bookmark.Type)]) + simpleEntry["Value"] = fmt.Sprintf("%d", bookmark.Value) case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK): l2Block := &datastream.L2Block{} err := proto.Unmarshal(entry.Data, l2Block) @@ -938,40 +958,24 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "L2 Block\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "L2 Block Number.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.Number)) - printColored(color.FgGreen, "Batch Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.BatchNumber)) - printColored(color.FgGreen, "Timestamp.......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d (%v)\n", l2Block.Timestamp, time.Unix(int64(l2Block.Timestamp), 0))) - printColored(color.FgGreen, "Delta Timestamp.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.DeltaTimestamp)) - printColored(color.FgGreen, "Min. Timestamp..: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.MinTimestamp)) - printColored(color.FgGreen, "L1 Block Hash...: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.L1Blockhash))) - printColored(color.FgGreen, "L1 InfoTree Idx.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.L1InfotreeIndex)) - printColored(color.FgGreen, "Block Hash......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.Hash))) - printColored(color.FgGreen, "State Root......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.StateRoot))) - printColored(color.FgGreen, "Global Exit Root: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.GlobalExitRoot))) - printColored(color.FgGreen, "Coinbase........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(l2Block.Coinbase))) - printColored(color.FgGreen, "Block Gas Limit.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2Block.BlockGasLimit)) - printColored(color.FgGreen, "Block Info Root.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToHash(l2Block.BlockInfoRoot))) + simpleEntry["Entry Type"] = "L2 Block" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["L2 Block Number"] = fmt.Sprintf("%d", l2Block.Number) + simpleEntry["Batch Number"] = fmt.Sprintf("%d", l2Block.BatchNumber) + simpleEntry["Timestamp"] = fmt.Sprintf("%d (%v)", l2Block.Timestamp, time.Unix(int64(l2Block.Timestamp), 0)) + simpleEntry["Delta Timestamp"] = fmt.Sprintf("%d", l2Block.DeltaTimestamp) + simpleEntry["Min. Timestamp"] = fmt.Sprintf("%d", l2Block.MinTimestamp) + simpleEntry["L1 Block Hash"] = fmt.Sprintf("%s", common.BytesToHash(l2Block.L1Blockhash)) + simpleEntry["L1 InfoTree Idx"] = fmt.Sprintf("%d", l2Block.L1InfotreeIndex) + simpleEntry["Block Hash"] = fmt.Sprintf("%s", common.BytesToHash(l2Block.Hash)) + simpleEntry["State Root"] = fmt.Sprintf("%s", common.BytesToHash(l2Block.StateRoot)) + simpleEntry["Global Exit Root"] = fmt.Sprintf("%s", common.BytesToHash(l2Block.GlobalExitRoot)) + simpleEntry["Coinbase"] = fmt.Sprintf("%s", common.BytesToAddress(l2Block.Coinbase)) + simpleEntry["Block Gas Limit"] = fmt.Sprintf("%d", l2Block.BlockGasLimit) + simpleEntry["Block Info Root"] = fmt.Sprintf("%s", common.BytesToHash(l2Block.BlockInfoRoot)) if l2Block.Debug != nil && l2Block.Debug.Message != "" { - printColored(color.FgGreen, "Debug...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", l2Block.Debug)) + simpleEntry["Debug"] = l2Block.Debug } case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END): @@ -982,12 +986,9 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "L2 Block End\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "L2 Block Number.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2BlockEnd.Number)) + simpleEntry["Entry Type"] = "L2 Block End" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["L2 Block Number"] = fmt.Sprintf("%d", l2BlockEnd.Number) case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_START): batch := &datastream.BatchStart{} @@ -996,22 +997,15 @@ func printEntry(entry datastreamer.FileEntry) { log.Error(err) os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "Batch Start\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "Batch Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.Number)) - printColored(color.FgGreen, "Batch Type......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", datastream.BatchType_name[int32(batch.Type)])) - printColored(color.FgGreen, "Fork ID.........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ForkId)) - printColored(color.FgGreen, "Chain ID........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.ChainId)) + simpleEntry["Entry Type"] = "Batch Start" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["Batch Number"] = fmt.Sprintf("%d", batch.Number) + simpleEntry["Batch Type"] = datastream.BatchType_name[int32(batch.Type)] + simpleEntry["Fork ID"] = fmt.Sprintf("%d", batch.ForkId) + simpleEntry["Chain ID "] = fmt.Sprintf("%d", batch.ChainId) if batch.Debug != nil && batch.Debug.Message != "" { - printColored(color.FgGreen, "Debug...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", batch.Debug)) + simpleEntry["Debug "] = batch.Debug } case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_END): @@ -1021,20 +1015,14 @@ func printEntry(entry datastreamer.FileEntry) { log.Error(err) os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "Batch End\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "Batch Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", batch.Number)) - printColored(color.FgGreen, "State Root......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.StateRoot))) - printColored(color.FgGreen, "Local Exit Root.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(batch.LocalExitRoot))) + simpleEntry["Entry Type"] = "Batch End" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["Batch Number"] = fmt.Sprintf("%d", batch.Number) + simpleEntry["State Root"] = "0x" + common.Bytes2Hex(batch.StateRoot) + simpleEntry["Local Exit Root"] = "0x" + common.Bytes2Hex(batch.LocalExitRoot) if batch.Debug != nil && batch.Debug.Message != "" { - printColored(color.FgGreen, "Debug...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", batch.Debug)) + simpleEntry["Debug "] = batch.Debug } case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION): @@ -1045,22 +1033,14 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "L2 Transaction\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "L2 Block Number.: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.L2BlockNumber)) - printColored(color.FgGreen, "Index...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.Index)) - printColored(color.FgGreen, "Is Valid........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%t\n", dsTx.IsValid)) - printColored(color.FgGreen, "Data............: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", "0x"+common.Bytes2Hex(dsTx.Encoded))) - printColored(color.FgGreen, "Effec. Gas Price: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", dsTx.EffectiveGasPricePercentage)) - printColored(color.FgGreen, "IM State Root...: ") - printColored(color.FgHiWhite, fmt.Sprint("0x"+common.Bytes2Hex(dsTx.ImStateRoot)+"\n")) + simpleEntry["Entry Type"] = "L2 Transaction" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["L2 Block Number"] = fmt.Sprintf("%d", dsTx.L2BlockNumber) + simpleEntry["Index"] = fmt.Sprintf("%d", dsTx.Index) + simpleEntry["Is Valid"] = fmt.Sprintf("%t", dsTx.IsValid) + simpleEntry["Data"] = "0x" + common.Bytes2Hex(dsTx.Encoded) + simpleEntry["Effec. Gas Price"] = fmt.Sprintf("%d", dsTx.EffectiveGasPricePercentage) + simpleEntry["IM State Root "] = fmt.Sprint("0x" + common.Bytes2Hex(dsTx.ImStateRoot)) tx, err := state.DecodeTx(common.Bytes2Hex(dsTx.Encoded)) if err != nil { @@ -1074,15 +1054,13 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Sender..........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", sender)) + simpleEntry["Sender"] = sender nonce := tx.Nonce() - printColored(color.FgGreen, "Nonce...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", nonce)) + + simpleEntry["Nonce "] = fmt.Sprintf("%d", nonce) if dsTx.Debug != nil && dsTx.Debug.Message != "" { - printColored(color.FgGreen, "Debug...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", dsTx.Debug)) + simpleEntry["Debug"] = dsTx.Debug } case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER): @@ -1093,33 +1071,67 @@ func printEntry(entry datastreamer.FileEntry) { os.Exit(1) } - printColored(color.FgGreen, "Entry Type......: ") - printColored(color.FgHiYellow, "Update GER\n") - printColored(color.FgGreen, "Entry Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number)) - printColored(color.FgGreen, "Batch Number....: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.BatchNumber)) - printColored(color.FgGreen, "Timestamp.......: ") - printColored(color.FgHiWhite, fmt.Sprintf("%v (%d)\n", time.Unix(int64(updateGer.Timestamp), 0), updateGer.Timestamp)) - printColored(color.FgGreen, "Global Exit Root: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.Bytes2Hex(updateGer.GlobalExitRoot))) - printColored(color.FgGreen, "Coinbase........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", common.BytesToAddress(updateGer.Coinbase))) - printColored(color.FgGreen, "Fork ID.........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ForkId)) - printColored(color.FgGreen, "Chain ID........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%d\n", updateGer.ChainId)) - printColored(color.FgGreen, "State Root......: ") - printColored(color.FgHiWhite, fmt.Sprint(common.Bytes2Hex(updateGer.StateRoot)+"\n")) + simpleEntry["Entry Type"] = "Update GER" + simpleEntry["Entry Number"] = fmt.Sprintf("%d", entry.Number) + simpleEntry["Batch Number"] = fmt.Sprintf("%d", updateGer.BatchNumber) + simpleEntry["Timestamp"] = fmt.Sprintf("%v (%d)", time.Unix(int64(updateGer.Timestamp), 0), updateGer.Timestamp) + simpleEntry["Global Exit Root"] = common.Bytes2Hex(updateGer.GlobalExitRoot) + simpleEntry["Coinbase"] = common.BytesToAddress(updateGer.Coinbase) + simpleEntry["Fork ID"] = fmt.Sprintf("%d", updateGer.ForkId) + simpleEntry["Chain ID"] = fmt.Sprintf("%d", updateGer.ChainId) + simpleEntry["State Root"] = fmt.Sprint(common.Bytes2Hex(updateGer.StateRoot)) if updateGer.Debug != nil && updateGer.Debug.Message != "" { - printColored(color.FgGreen, "Debug...........: ") - printColored(color.FgHiWhite, fmt.Sprintf("%s\n", updateGer.Debug)) + simpleEntry["Debug"] = updateGer.Debug } } + + // why bother + if len(simpleEntry) == 0 { + return + } + if shouldPrintJson { + printJSON(simpleEntry) + } else { + printColorful(simpleEntry) + } } func printColored(color color.Attribute, text string) { colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", color, text) fmt.Print(colored) } +func printJSON(item any) { + jsonBytes, err := json.Marshal(item) + if err != nil { + log.Error(err) + os.Exit(1) + } + fmt.Println(string(jsonBytes)) +} + +// ColorfulFieldWidth specifies the padded width of the field name of the colorful output +const ColorfulFieldWidth = 25 + +func printColorful(entry map[string]any) { + entryType, hasKey := entry["Entry Type"] + if hasKey { + pad := strings.Repeat("·", ColorfulFieldWidth-len("Entry Type")) + fmt.Printf("\x1b[%dm%s\x1b[0m%s: \x1b[%dm%s\x1b[0m\n", color.FgGreen, "Entry Type", pad, color.FgYellow, entryType) + } + + keys := getSortedEntryKeys(entry) + for _, k := range keys { + v := entry[k] + pad := strings.Repeat("·", ColorfulFieldWidth-len(k)) + fmt.Printf("\x1b[%dm%s\x1b[0m%s: \x1b[%dm%s\x1b[0m\n", color.FgGreen, k, pad, color.FgWhite, v) + } +} +func getSortedEntryKeys(entry map[string]any) []string { + keys := make([]string, 0) + for k := range entry { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +}