synapsecns/sanguine

View on GitHub
services/scribe/db/receipt_test.go

Summary

Maintainability
B
6 hrs
Test Coverage
package db_test

import (
    "math/big"

    "github.com/brianvoe/gofakeit/v6"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/core/types"
    . "github.com/stretchr/testify/assert"
    "github.com/synapsecns/sanguine/services/scribe/db"
)

func (t *DBSuite) TestStoreRetrieveReceipt() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        txHashRandom := gofakeit.Int64()
        chainID := gofakeit.Uint32()
        txHashA := common.BigToHash(big.NewInt(txHashRandom))
        txHashB := common.BigToHash(big.NewInt(txHashRandom + 1))
        randomLogsA := []types.Log{
            t.MakeRandomLog(txHashA),
            t.MakeRandomLog(txHashA),
        }
        randomLogsA[0].BlockNumber = 4
        randomLogsA[1].BlockNumber = 3
        randomLogsB := []types.Log{
            t.MakeRandomLog(txHashB),
            t.MakeRandomLog(txHashB),
        }
        randomLogsB[0].BlockNumber = 2
        randomLogsB[1].BlockNumber = 1

        // Store all random logs, since `RetrieveReceipt` needs to query them to build the Receipt.
        for _, log := range randomLogsA {
            err := testDB.StoreLogs(t.GetTestContext(), chainID, log)
            Nil(t.T(), err)
        }
        for _, log := range randomLogsB {
            err := testDB.StoreLogs(t.GetTestContext(), chainID+1, log)
            Nil(t.T(), err)
        }

        // Store two receipts with different tx hashes.
        receiptA := types.Receipt{
            Type:              gofakeit.Uint8(),
            PostState:         []byte(gofakeit.Sentence(10)),
            Status:            gofakeit.Uint64(),
            CumulativeGasUsed: gofakeit.Uint64(),
            Bloom:             types.BytesToBloom([]byte(gofakeit.Sentence(10))),
            Logs: []*types.Log{
                &randomLogsA[0],
                &randomLogsA[1],
            },
            TxHash:           txHashA,
            ContractAddress:  common.BigToAddress(big.NewInt(gofakeit.Int64())),
            GasUsed:          gofakeit.Uint64(),
            BlockNumber:      big.NewInt(1),
            TransactionIndex: uint(gofakeit.Uint64()),
        }
        err := testDB.StoreReceipt(t.GetTestContext(), chainID, receiptA)
        Nil(t.T(), err)

        receiptB := types.Receipt{
            Type:              gofakeit.Uint8(),
            PostState:         []byte(gofakeit.Sentence(10)),
            Status:            gofakeit.Uint64(),
            CumulativeGasUsed: gofakeit.Uint64(),
            Bloom:             types.BytesToBloom([]byte(gofakeit.Sentence(10))),
            Logs: []*types.Log{
                &randomLogsB[0],
                &randomLogsB[1],
            },
            TxHash:           txHashB,
            ContractAddress:  common.BigToAddress(big.NewInt(gofakeit.Int64())),
            GasUsed:          gofakeit.Uint64(),
            BlockNumber:      big.NewInt(2),
            TransactionIndex: uint(gofakeit.Uint64()),
        }
        err = testDB.StoreReceipt(t.GetTestContext(), chainID+1, receiptB)
        Nil(t.T(), err)

        // Ensure the receipts from the database match the ones stored.
        receiptFilter := db.ReceiptFilter{
            TxHash:  txHashA.String(),
            ChainID: chainID,
        }
        retrievedReceiptA, err := testDB.RetrieveReceiptsWithFilter(t.GetTestContext(), receiptFilter, 1)
        Nil(t.T(), err)

        resA, err := receiptA.MarshalJSON()
        Nil(t.T(), err)
        resB, err := retrievedReceiptA[0].MarshalJSON()
        Nil(t.T(), err)
        Equal(t.T(), resA, resB)

        receiptFilter = db.ReceiptFilter{
            TxHash:  txHashB.String(),
            ChainID: chainID + 1,
        }
        retrievedReceiptB, err := testDB.RetrieveReceiptsWithFilter(t.GetTestContext(), receiptFilter, 1)
        Nil(t.T(), err)

        resA, err = receiptB.MarshalJSON()
        Nil(t.T(), err)
        resB, err = retrievedReceiptB[0].MarshalJSON()
        Nil(t.T(), err)
        Equal(t.T(), resA, resB)

        // Ensure RetrieveAllReceipts gets all receipts.
        allReceipts, err := testDB.RetrieveReceiptsWithFilter(t.GetTestContext(), db.ReceiptFilter{}, 1)
        Nil(t.T(), err)
        Equal(t.T(), 2, len(allReceipts))
    })
}

func (t *DBSuite) TestDeleteReceiptsForBlockHash() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()

        // Store a receipt.
        receipt := t.MakeRandomReceipt(common.BigToHash(big.NewInt(gofakeit.Int64())))
        receipt.BlockHash = common.BigToHash(big.NewInt(5))
        err := testDB.StoreReceipt(t.GetTestContext(), chainID, receipt)
        Nil(t.T(), err)

        // Ensure the receipt is in the database.
        receiptFilter := db.ReceiptFilter{
            ChainID:   chainID,
            BlockHash: receipt.BlockHash.String(),
        }
        retrievedReceipts, err := testDB.RetrieveReceiptsWithFilter(t.GetTestContext(), receiptFilter, 1)
        Nil(t.T(), err)
        Equal(t.T(), 1, len(retrievedReceipts))

        // Delete the receipt.
        err = testDB.DeleteReceiptsForBlockHash(t.GetTestContext(), chainID, receipt.BlockHash)
        Nil(t.T(), err)

        // Ensure the receipt is not in the database.
        retrievedReceipts, err = testDB.RetrieveReceiptsWithFilter(t.GetTestContext(), receiptFilter, 1)
        Nil(t.T(), err)
        Equal(t.T(), 0, len(retrievedReceipts))
    })
}

func (t *DBSuite) MakeRandomReceipt(txHash common.Hash) types.Receipt {
    return types.Receipt{
        Type:              gofakeit.Uint8(),
        PostState:         []byte(gofakeit.Sentence(10)),
        Status:            gofakeit.Uint64(),
        CumulativeGasUsed: gofakeit.Uint64(),
        Bloom:             types.BytesToBloom([]byte(gofakeit.Sentence(10))),
        Logs:              []*types.Log{},
        TxHash:            txHash,
        ContractAddress:   common.BigToAddress(big.NewInt(gofakeit.Int64())),
        GasUsed:           gofakeit.Uint64(),
        BlockNumber:       big.NewInt(int64(gofakeit.Uint32())),
        TransactionIndex:  uint(gofakeit.Uint64()),
    }
}

func (t *DBSuite) TestRetrieveReceiptsWithStaleBlockHash() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()
        startBlock := 2
        hash1 := common.BigToHash(big.NewInt(1))
        hash2 := common.BigToHash(big.NewInt(2))
        hash3 := common.BigToHash(big.NewInt(3))
        newHash2 := common.BigToHash(big.NewInt(22))
        blockHashes := []common.Hash{hash1, hash2, hash3}
        blockHashesStr := []string{hash1.String(), newHash2.String(), hash3.String()}

        for i := 0; i < 10; i++ {
            receipt := t.MakeRandomReceipt(common.BigToHash(big.NewInt(gofakeit.Int64())))
            receipt.BlockNumber = big.NewInt(int64(i))
            receipt.BlockHash = blockHashes[i%3]
            err := testDB.StoreReceipt(t.GetTestContext(), chainID, receipt)
            Nil(t.T(), err)
        }

        // Retrieve the receipts
        retrievedReceipts, err := testDB.RetrieveReceiptsWithStaleBlockHash(t.GetTestContext(), chainID, blockHashesStr, uint64(startBlock), 10)
        Nil(t.T(), err)

        // Ensure the correct receipts (all the ones with hash 2) were retrieved
        Equal(t.T(), 2, len(retrievedReceipts))
        Equal(t.T(), hash2, retrievedReceipts[0].BlockHash)
    })
}