services/scribe/db/receipt_test.go
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)
})
}