github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/rollup/rollup_sync_service/block.go (about) 1 package rollup_sync_service 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "fmt" 7 "math" 8 "math/big" 9 10 "github.com/scroll-tech/go-ethereum/common" 11 "github.com/scroll-tech/go-ethereum/common/hexutil" 12 "github.com/scroll-tech/go-ethereum/core/types" 13 ) 14 15 const blockContextByteSize = 60 16 17 // WrappedBlock contains the block's Header, Transactions and WithdrawTrieRoot hash. 18 type WrappedBlock struct { 19 Header *types.Header `json:"header"` 20 // Transactions is only used for recover types.Transactions, the from of types.TransactionData field is missing. 21 Transactions []*types.TransactionData `json:"transactions"` 22 WithdrawRoot common.Hash `json:"withdraw_trie_root,omitempty"` 23 } 24 25 // BlockContext represents the essential data of a block in the ScrollChain. 26 // It provides an overview of block attributes including hash values, block numbers, gas details, and transaction counts. 27 type BlockContext struct { 28 BlockHash common.Hash 29 ParentHash common.Hash 30 BlockNumber uint64 31 Timestamp uint64 32 BaseFee *big.Int 33 GasLimit uint64 34 NumTransactions uint16 35 NumL1Messages uint16 36 } 37 38 // numL1Messages returns the number of L1 messages in this block. 39 // This number is the sum of included and skipped L1 messages. 40 func (w *WrappedBlock) numL1Messages(totalL1MessagePoppedBefore uint64) uint64 { 41 var lastQueueIndex *uint64 42 for _, txData := range w.Transactions { 43 if txData.Type == types.L1MessageTxType { 44 lastQueueIndex = &txData.Nonce 45 } 46 } 47 if lastQueueIndex == nil { 48 return 0 49 } 50 // note: last queue index included before this block is totalL1MessagePoppedBefore - 1 51 // TODO: cache results 52 return *lastQueueIndex - totalL1MessagePoppedBefore + 1 53 } 54 55 // Encode encodes the WrappedBlock into RollupV2 BlockContext Encoding. 56 func (w *WrappedBlock) Encode(totalL1MessagePoppedBefore uint64) ([]byte, error) { 57 bytes := make([]byte, 60) 58 59 if !w.Header.Number.IsUint64() { 60 return nil, errors.New("block number is not uint64") 61 } 62 63 // note: numL1Messages includes skipped messages 64 numL1Messages := w.numL1Messages(totalL1MessagePoppedBefore) 65 if numL1Messages > math.MaxUint16 { 66 return nil, errors.New("number of L1 messages exceeds max uint16") 67 } 68 69 // note: numTransactions includes skipped messages 70 numL2Transactions := w.numL2Transactions() 71 numTransactions := numL1Messages + numL2Transactions 72 if numTransactions > math.MaxUint16 { 73 return nil, errors.New("number of transactions exceeds max uint16") 74 } 75 76 binary.BigEndian.PutUint64(bytes[0:], w.Header.Number.Uint64()) 77 binary.BigEndian.PutUint64(bytes[8:], w.Header.Time) 78 // TODO: [16:47] Currently, baseFee is 0, because we disable EIP-1559. 79 binary.BigEndian.PutUint64(bytes[48:], w.Header.GasLimit) 80 binary.BigEndian.PutUint16(bytes[56:], uint16(numTransactions)) 81 binary.BigEndian.PutUint16(bytes[58:], uint16(numL1Messages)) 82 83 return bytes, nil 84 } 85 86 func txsToTxsData(txs types.Transactions) []*types.TransactionData { 87 txsData := make([]*types.TransactionData, len(txs)) 88 for i, tx := range txs { 89 v, r, s := tx.RawSignatureValues() 90 91 nonce := tx.Nonce() 92 93 // We need QueueIndex in `NewBatchHeader`. However, `TransactionData` 94 // does not have this field. Since `L1MessageTx` do not have a nonce, 95 // we reuse this field for storing the queue index. 96 if msg := tx.AsL1MessageTx(); msg != nil { 97 nonce = msg.QueueIndex 98 } 99 100 txsData[i] = &types.TransactionData{ 101 Type: tx.Type(), 102 TxHash: tx.Hash().String(), 103 Nonce: nonce, 104 ChainId: (*hexutil.Big)(tx.ChainId()), 105 Gas: tx.Gas(), 106 GasPrice: (*hexutil.Big)(tx.GasPrice()), 107 To: tx.To(), 108 Value: (*hexutil.Big)(tx.Value()), 109 Data: hexutil.Encode(tx.Data()), 110 IsCreate: tx.To() == nil, 111 V: (*hexutil.Big)(v), 112 R: (*hexutil.Big)(r), 113 S: (*hexutil.Big)(s), 114 } 115 } 116 return txsData 117 } 118 119 func convertTxDataToRLPEncoding(txData *types.TransactionData) ([]byte, error) { 120 data, err := hexutil.Decode(txData.Data) 121 if err != nil { 122 return nil, fmt.Errorf("failed to decode txData.Data: %s, err: %w", txData.Data, err) 123 } 124 125 tx := types.NewTx(&types.LegacyTx{ 126 Nonce: txData.Nonce, 127 To: txData.To, 128 Value: txData.Value.ToInt(), 129 Gas: txData.Gas, 130 GasPrice: txData.GasPrice.ToInt(), 131 Data: data, 132 V: txData.V.ToInt(), 133 R: txData.R.ToInt(), 134 S: txData.S.ToInt(), 135 }) 136 137 rlpTxData, err := tx.MarshalBinary() 138 if err != nil { 139 return nil, fmt.Errorf("failed to marshal binary of the tx: %+v, err: %w", tx, err) 140 } 141 142 return rlpTxData, nil 143 } 144 145 func (w *WrappedBlock) numL2Transactions() uint64 { 146 var count uint64 147 for _, txData := range w.Transactions { 148 if txData.Type != types.L1MessageTxType { 149 count++ 150 } 151 } 152 return count 153 } 154 155 func decodeBlockContext(encodedBlockContext []byte) (*BlockContext, error) { 156 if len(encodedBlockContext) != blockContextByteSize { 157 return nil, errors.New("block encoding is not 60 bytes long") 158 } 159 160 return &BlockContext{ 161 BlockNumber: binary.BigEndian.Uint64(encodedBlockContext[0:8]), 162 Timestamp: binary.BigEndian.Uint64(encodedBlockContext[8:16]), 163 GasLimit: binary.BigEndian.Uint64(encodedBlockContext[48:56]), 164 NumTransactions: binary.BigEndian.Uint16(encodedBlockContext[56:58]), 165 NumL1Messages: binary.BigEndian.Uint16(encodedBlockContext[58:60]), 166 }, nil 167 }