@@ -94,7 +94,28 @@ type receiptRLP struct {
9494type storedReceiptRLP struct {
9595 PostStateOrStatus []byte
9696 CumulativeGasUsed uint64
97- Logs []* Log
97+ Logs []* LogForStorage
98+ }
99+
100+ // v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
101+ type v4StoredReceiptRLP struct {
102+ PostStateOrStatus []byte
103+ CumulativeGasUsed uint64
104+ TxHash common.Hash
105+ ContractAddress common.Address
106+ Logs []* LogForStorage
107+ GasUsed uint64
108+ }
109+
110+ // v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields.
111+ type v3StoredReceiptRLP struct {
112+ PostStateOrStatus []byte
113+ CumulativeGasUsed uint64
114+ Bloom Bloom
115+ TxHash common.Hash
116+ ContractAddress common.Address
117+ Logs []* LogForStorage
118+ GasUsed uint64
98119}
99120
100121// NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -212,28 +233,96 @@ func (r *Receipt) Size() common.StorageSize {
212233// entire content of a receipt, as opposed to only the consensus fields originally.
213234type ReceiptForStorage Receipt
214235
215- // EncodeRLP implements rlp.Encoder.
236+ // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
237+ // into an RLP stream.
216238func (r * ReceiptForStorage ) EncodeRLP (w io.Writer ) error {
217239 enc := & storedReceiptRLP {
218240 PostStateOrStatus : (* Receipt )(r ).statusEncoding (),
219241 CumulativeGasUsed : r .CumulativeGasUsed ,
220- Logs : r .Logs ,
242+ Logs : make ([]* LogForStorage , len (r .Logs )),
243+ }
244+ for i , log := range r .Logs {
245+ enc .Logs [i ] = (* LogForStorage )(log )
221246 }
222247 return rlp .Encode (w , enc )
223248}
224249
225- // DecodeRLP implements rlp.Decoder.
250+ // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
251+ // fields of a receipt from an RLP stream.
226252func (r * ReceiptForStorage ) DecodeRLP (s * rlp.Stream ) error {
253+ // Retrieve the entire receipt blob as we need to try multiple decoders
254+ blob , err := s .Raw ()
255+ if err != nil {
256+ return err
257+ }
258+ // Try decoding from the newest format for future proofness, then the older one
259+ // for old nodes that just upgraded. V4 was an intermediate unreleased format so
260+ // we do need to decode it, but it's not common (try last).
261+ if err := decodeStoredReceiptRLP (r , blob ); err == nil {
262+ return nil
263+ }
264+ if err := decodeV3StoredReceiptRLP (r , blob ); err == nil {
265+ return nil
266+ }
267+ return decodeV4StoredReceiptRLP (r , blob )
268+ }
269+
270+ func decodeStoredReceiptRLP (r * ReceiptForStorage , blob []byte ) error {
227271 var stored storedReceiptRLP
228- if err := s . Decode ( & stored ); err != nil {
272+ if err := rlp . DecodeBytes ( blob , & stored ); err != nil {
229273 return err
230274 }
231275 if err := (* Receipt )(r ).setStatus (stored .PostStateOrStatus ); err != nil {
232276 return err
233277 }
234278 r .CumulativeGasUsed = stored .CumulativeGasUsed
235- r .Logs = stored .Logs
279+ r .Logs = make ([]* Log , len (stored .Logs ))
280+ for i , log := range stored .Logs {
281+ r .Logs [i ] = (* Log )(log )
282+ }
236283 r .Bloom = CreateBloom (Receipts {(* Receipt )(r )})
284+
285+ return nil
286+ }
287+
288+ func decodeV4StoredReceiptRLP (r * ReceiptForStorage , blob []byte ) error {
289+ var stored v4StoredReceiptRLP
290+ if err := rlp .DecodeBytes (blob , & stored ); err != nil {
291+ return err
292+ }
293+ if err := (* Receipt )(r ).setStatus (stored .PostStateOrStatus ); err != nil {
294+ return err
295+ }
296+ r .CumulativeGasUsed = stored .CumulativeGasUsed
297+ r .TxHash = stored .TxHash
298+ r .ContractAddress = stored .ContractAddress
299+ r .GasUsed = stored .GasUsed
300+ r .Logs = make ([]* Log , len (stored .Logs ))
301+ for i , log := range stored .Logs {
302+ r .Logs [i ] = (* Log )(log )
303+ }
304+ r .Bloom = CreateBloom (Receipts {(* Receipt )(r )})
305+
306+ return nil
307+ }
308+
309+ func decodeV3StoredReceiptRLP (r * ReceiptForStorage , blob []byte ) error {
310+ var stored v3StoredReceiptRLP
311+ if err := rlp .DecodeBytes (blob , & stored ); err != nil {
312+ return err
313+ }
314+ if err := (* Receipt )(r ).setStatus (stored .PostStateOrStatus ); err != nil {
315+ return err
316+ }
317+ r .CumulativeGasUsed = stored .CumulativeGasUsed
318+ r .Bloom = stored .Bloom
319+ r .TxHash = stored .TxHash
320+ r .ContractAddress = stored .ContractAddress
321+ r .GasUsed = stored .GasUsed
322+ r .Logs = make ([]* Log , len (stored .Logs ))
323+ for i , log := range stored .Logs {
324+ r .Logs [i ] = (* Log )(log )
325+ }
237326 return nil
238327}
239328
0 commit comments