@@ -670,3 +670,216 @@ func makeTestReceipts(n int, nPerBlock int) []types.Receipts {
670670 }
671671 return allReceipts
672672}
673+
674+ type fullLogRLP struct {
675+ Address common.Address
676+ Topics []common.Hash
677+ Data []byte
678+ BlockNumber uint64
679+ TxHash common.Hash
680+ TxIndex uint
681+ BlockHash common.Hash
682+ Index uint
683+ }
684+
685+ func newFullLogRLP (l * types.Log ) * fullLogRLP {
686+ return & fullLogRLP {
687+ Address : l .Address ,
688+ Topics : l .Topics ,
689+ Data : l .Data ,
690+ BlockNumber : l .BlockNumber ,
691+ TxHash : l .TxHash ,
692+ TxIndex : l .TxIndex ,
693+ BlockHash : l .BlockHash ,
694+ Index : l .Index ,
695+ }
696+ }
697+
698+ // Tests that logs associated with a single block can be retrieved.
699+ func TestReadLogs (t * testing.T ) {
700+ db := NewMemoryDatabase ()
701+
702+ // Create a live block since we need metadata to reconstruct the receipt
703+ tx1 := types .NewTransaction (1 , common .HexToAddress ("0x1" ), big .NewInt (1 ), 1 , big .NewInt (1 ), nil )
704+ tx2 := types .NewTransaction (2 , common .HexToAddress ("0x2" ), big .NewInt (2 ), 2 , big .NewInt (2 ), nil )
705+
706+ body := & types.Body {Transactions : types.Transactions {tx1 , tx2 }}
707+
708+ // Create the two receipts to manage afterwards
709+ receipt1 := & types.Receipt {
710+ Status : types .ReceiptStatusFailed ,
711+ CumulativeGasUsed : 1 ,
712+ Logs : []* types.Log {
713+ {Address : common .BytesToAddress ([]byte {0x11 })},
714+ {Address : common .BytesToAddress ([]byte {0x01 , 0x11 })},
715+ },
716+ TxHash : tx1 .Hash (),
717+ ContractAddress : common .BytesToAddress ([]byte {0x01 , 0x11 , 0x11 }),
718+ GasUsed : 111111 ,
719+ }
720+ receipt1 .Bloom = types .CreateBloom (types.Receipts {receipt1 })
721+
722+ receipt2 := & types.Receipt {
723+ PostState : common.Hash {2 }.Bytes (),
724+ CumulativeGasUsed : 2 ,
725+ Logs : []* types.Log {
726+ {Address : common .BytesToAddress ([]byte {0x22 })},
727+ {Address : common .BytesToAddress ([]byte {0x02 , 0x22 })},
728+ },
729+ TxHash : tx2 .Hash (),
730+ ContractAddress : common .BytesToAddress ([]byte {0x02 , 0x22 , 0x22 }),
731+ GasUsed : 222222 ,
732+ }
733+ receipt2 .Bloom = types .CreateBloom (types.Receipts {receipt2 })
734+ receipts := []* types.Receipt {receipt1 , receipt2 }
735+
736+ hash := common .BytesToHash ([]byte {0x03 , 0x14 })
737+ // Check that no receipt entries are in a pristine database
738+ if rs := ReadReceipts (db , hash , 0 , params .TestChainConfig ); len (rs ) != 0 {
739+ t .Fatalf ("non existent receipts returned: %v" , rs )
740+ }
741+ // Insert the body that corresponds to the receipts
742+ WriteBody (db , hash , 0 , body )
743+
744+ // Insert the receipt slice into the database and check presence
745+ WriteReceipts (db , hash , 0 , receipts )
746+
747+ logs := ReadLogs (db , hash , 0 )
748+ if len (logs ) == 0 {
749+ t .Fatalf ("no logs returned" )
750+ }
751+ if have , want := len (logs ), 2 ; have != want {
752+ t .Fatalf ("unexpected number of logs returned, have %d want %d" , have , want )
753+ }
754+ if have , want := len (logs [0 ]), 2 ; have != want {
755+ t .Fatalf ("unexpected number of logs[0] returned, have %d want %d" , have , want )
756+ }
757+ if have , want := len (logs [1 ]), 2 ; have != want {
758+ t .Fatalf ("unexpected number of logs[1] returned, have %d want %d" , have , want )
759+ }
760+
761+ // Fill in log fields so we can compare their rlp encoding
762+ if err := types .Receipts (receipts ).DeriveFields (params .TestChainConfig , hash , 0 , body .Transactions ); err != nil {
763+ t .Fatal (err )
764+ }
765+ for i , pr := range receipts {
766+ for j , pl := range pr .Logs {
767+ rlpHave , err := rlp .EncodeToBytes (newFullLogRLP (logs [i ][j ]))
768+ if err != nil {
769+ t .Fatal (err )
770+ }
771+ rlpWant , err := rlp .EncodeToBytes (newFullLogRLP (pl ))
772+ if err != nil {
773+ t .Fatal (err )
774+ }
775+ if ! bytes .Equal (rlpHave , rlpWant ) {
776+ t .Fatalf ("receipt #%d: receipt mismatch: have %s, want %s" , i , hex .EncodeToString (rlpHave ), hex .EncodeToString (rlpWant ))
777+ }
778+ }
779+ }
780+ }
781+
782+ func TestDeriveLogFields (t * testing.T ) {
783+ // Create a few transactions to have receipts for
784+ to2 := common .HexToAddress ("0x2" )
785+ to3 := common .HexToAddress ("0x3" )
786+ txs := types.Transactions {
787+ types .NewTx (& types.LegacyTx {
788+ Nonce : 1 ,
789+ Value : big .NewInt (1 ),
790+ Gas : 1 ,
791+ GasPrice : big .NewInt (1 ),
792+ }),
793+ types .NewTx (& types.LegacyTx {
794+ To : & to2 ,
795+ Nonce : 2 ,
796+ Value : big .NewInt (2 ),
797+ Gas : 2 ,
798+ GasPrice : big .NewInt (2 ),
799+ }),
800+ types .NewTx (& types.AccessListTx {
801+ To : & to3 ,
802+ Nonce : 3 ,
803+ Value : big .NewInt (3 ),
804+ Gas : 3 ,
805+ GasPrice : big .NewInt (3 ),
806+ }),
807+ }
808+ // Create the corresponding receipts
809+ receipts := []* receiptLogs {
810+ {
811+ Logs : []* types.Log {
812+ {Address : common .BytesToAddress ([]byte {0x11 })},
813+ {Address : common .BytesToAddress ([]byte {0x01 , 0x11 })},
814+ },
815+ },
816+ {
817+ Logs : []* types.Log {
818+ {Address : common .BytesToAddress ([]byte {0x22 })},
819+ {Address : common .BytesToAddress ([]byte {0x02 , 0x22 })},
820+ },
821+ },
822+ {
823+ Logs : []* types.Log {
824+ {Address : common .BytesToAddress ([]byte {0x33 })},
825+ {Address : common .BytesToAddress ([]byte {0x03 , 0x33 })},
826+ },
827+ },
828+ }
829+
830+ // Derive log metadata fields
831+ number := big .NewInt (1 )
832+ hash := common .BytesToHash ([]byte {0x03 , 0x14 })
833+ if err := deriveLogFields (receipts , hash , number .Uint64 (), txs ); err != nil {
834+ t .Fatal (err )
835+ }
836+
837+ // Iterate over all the computed fields and check that they're correct
838+ logIndex := uint (0 )
839+ for i := range receipts {
840+ for j := range receipts [i ].Logs {
841+ if receipts [i ].Logs [j ].BlockNumber != number .Uint64 () {
842+ t .Errorf ("receipts[%d].Logs[%d].BlockNumber = %d, want %d" , i , j , receipts [i ].Logs [j ].BlockNumber , number .Uint64 ())
843+ }
844+ if receipts [i ].Logs [j ].BlockHash != hash {
845+ t .Errorf ("receipts[%d].Logs[%d].BlockHash = %s, want %s" , i , j , receipts [i ].Logs [j ].BlockHash .String (), hash .String ())
846+ }
847+ if receipts [i ].Logs [j ].TxHash != txs [i ].Hash () {
848+ t .Errorf ("receipts[%d].Logs[%d].TxHash = %s, want %s" , i , j , receipts [i ].Logs [j ].TxHash .String (), txs [i ].Hash ().String ())
849+ }
850+ if receipts [i ].Logs [j ].TxIndex != uint (i ) {
851+ t .Errorf ("receipts[%d].Logs[%d].TransactionIndex = %d, want %d" , i , j , receipts [i ].Logs [j ].TxIndex , i )
852+ }
853+ if receipts [i ].Logs [j ].Index != logIndex {
854+ t .Errorf ("receipts[%d].Logs[%d].Index = %d, want %d" , i , j , receipts [i ].Logs [j ].Index , logIndex )
855+ }
856+ logIndex ++
857+ }
858+ }
859+ }
860+
861+ func BenchmarkDecodeRLPLogs (b * testing.B ) {
862+ // Encoded receipts from block 0x14ee094309fbe8f70b65f45ebcc08fb33f126942d97464aad5eb91cfd1e2d269
863+ buf , err := ioutil .ReadFile ("testdata/stored_receipts.bin" )
864+ if err != nil {
865+ b .Fatal (err )
866+ }
867+ b .Run ("ReceiptForStorage" , func (b * testing.B ) {
868+ b .ReportAllocs ()
869+ var r []* types.ReceiptForStorage
870+ for i := 0 ; i < b .N ; i ++ {
871+ if err := rlp .DecodeBytes (buf , & r ); err != nil {
872+ b .Fatal (err )
873+ }
874+ }
875+ })
876+ b .Run ("rlpLogs" , func (b * testing.B ) {
877+ b .ReportAllocs ()
878+ var r []* receiptLogs
879+ for i := 0 ; i < b .N ; i ++ {
880+ if err := rlp .DecodeBytes (buf , & r ); err != nil {
881+ b .Fatal (err )
882+ }
883+ }
884+ })
885+ }
0 commit comments