synapsecns/sanguine

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

Summary

Maintainability
D
2 days
Test Coverage
package db_test

import (
    "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/ethergo/signer/signer/localsigner"
    "github.com/synapsecns/sanguine/ethergo/signer/wallet"
    "github.com/synapsecns/sanguine/services/scribe/db"
    scribeTypes "github.com/synapsecns/sanguine/services/scribe/types"
    "math/big"
    "time"
)

func (t *DBSuite) TestUnconfirmedLogsQuery() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()
        contractAddress := common.BigToAddress(big.NewInt(gofakeit.Int64()))
        const confirmedBlockHeight = 100
        const headBlock = 110
        for i := 1; i <= confirmedBlockHeight; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))
            log := t.MakeRandomLog(txHash)
            log.BlockNumber = uint64(i)
            log.Address = contractAddress
            // For testing, all confirmed txs will have an index of 1
            log.Index = 1
            err := testDB.StoreLogs(t.GetTestContext(), chainID, log)
            Nil(t.T(), err)
        }
        err := testDB.StoreLastIndexed(t.GetTestContext(), contractAddress, chainID, confirmedBlockHeight, scribeTypes.IndexingConfirmed)
        Nil(t.T(), err)

        // For testing, having the same txhash for all unconfirmed blocks.
        for i := confirmedBlockHeight + 1; i <= headBlock; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))

            log := t.MakeRandomLog(txHash)
            log.BlockNumber = uint64(i)
            log.TxHash = common.BigToHash(big.NewInt(gofakeit.Int64()))
            log.Address = contractAddress
            // For testing, all unconfirmed txs will have an index of 0
            log.Index = 0
            err := testDB.StoreLogsAtHead(t.GetTestContext(), chainID, log)
            Nil(t.T(), err)
        }

        logFilter := db.LogFilter{
            ChainID:         chainID,
            ContractAddress: contractAddress.String(),
        }
        logs, err := testDB.RetrieveLogsFromHeadRangeQuery(t.GetTestContext(), logFilter, 0, headBlock, 1)
        Nil(t.T(), err)
        Equal(t.T(), 100, len(logs))
        if len(logs) == 100 {
            Equal(t.T(), uint(0), logs[0].Index)
            // Check block range
            Equal(t.T(), uint64(110), logs[0].BlockNumber)
            Equal(t.T(), uint64(11), logs[99].BlockNumber)
            // check threshold of confirmed vs unconfirmed
            Equal(t.T(), uint(1), logs[10].Index)
            Equal(t.T(), uint(0), logs[9].Index)
        }
        logs, err = testDB.RetrieveLogsFromHeadRangeQuery(t.GetTestContext(), logFilter, 0, headBlock, 2)
        Nil(t.T(), err)

        Equal(t.T(), 10, len(logs))
        if len(logs) == 10 {
            // Check that these are confirmed logs
            Equal(t.T(), uint(1), logs[0].Index)
        }
    })
}

func (t *DBSuite) TestFlushLog() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()
        contractAddress := common.BigToAddress(big.NewInt(gofakeit.Int64()))
        const deleteUpToBlock = 110
        const desiredBlockHeight = 200
        for i := 1; i <= deleteUpToBlock; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))
            log := t.MakeRandomLog(txHash)
            log.BlockNumber = uint64(i)
            log.Address = contractAddress

            // For testing, all to delete txs will have an index of 1
            log.Index = 1
            err := testDB.StoreLogsAtHead(t.GetTestContext(), chainID, log)
            Nil(t.T(), err)
        }
        time.Sleep(1 * time.Second)
        deleteTimestamp := time.Now().UnixNano()
        for i := deleteUpToBlock + 1; i <= desiredBlockHeight; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))

            log := t.MakeRandomLog(txHash)
            log.BlockNumber = uint64(i)
            log.TxHash = common.BigToHash(big.NewInt(gofakeit.Int64()))
            log.Address = contractAddress
            // For testing, all no delete txs will have an index of 0
            log.Index = 0
            err := testDB.StoreLogsAtHead(t.GetTestContext(), chainID, log)
            Nil(t.T(), err)
        }
        logFilter := db.LogFilter{
            ChainID:         chainID,
            ContractAddress: contractAddress.String(),
        }
        logs, err := testDB.RetrieveLogsFromHeadRangeQuery(t.GetTestContext(), logFilter, 0, desiredBlockHeight, 1)
        Nil(t.T(), err)
        Equal(t.T(), 100, len(logs))
        if 100 == len(logs) {
            Equal(t.T(), uint64(desiredBlockHeight), logs[0].BlockNumber)
        }
        err = testDB.FlushFromHeadTables(t.GetTestContext(), deleteTimestamp)
        Nil(t.T(), err)
        logs, err = testDB.RetrieveLogsFromHeadRangeQuery(t.GetTestContext(), logFilter, 0, desiredBlockHeight, 1)
        Nil(t.T(), err)
        Equal(t.T(), 90, len(logs))
        if len(logs) == 90 {
            // Check that the earliest log has a timestamp of 110
            Equal(t.T(), uint(0), logs[0].Index)
            Equal(t.T(), uint64(desiredBlockHeight), logs[0].BlockNumber)
        }
    })
}

// nolint:dupl
func (t *DBSuite) TestUnconfirmedTxsQuery() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()
        const lastIndexed = 100
        const confirmedBlockHeight = 100
        const headBlock = 110
        testWallet, err := wallet.FromRandom()
        Nil(t.T(), err)
        signer := localsigner.NewSigner(testWallet.PrivateKey())

        for i := 1; i <= confirmedBlockHeight; i++ {
            // Nonce is used to determine if a tx is confirmed or not
            testTx := types.NewTx(&types.LegacyTx{
                Nonce:    uint64(1),
                GasPrice: new(big.Int).SetUint64(gofakeit.Uint64()),
                Gas:      gofakeit.Uint64(),
                To:       addressPtr(common.BigToAddress(new(big.Int).SetUint64(gofakeit.Uint64()))),
                Value:    new(big.Int).SetUint64(gofakeit.Uint64()),
                Data:     []byte(gofakeit.Paragraph(1, 2, 3, " ")),
            })
            transactor, err := localsigner.NewSigner(testWallet.PrivateKey()).GetTransactor(t.GetTestContext(), testTx.ChainId())
            Nil(t.T(), err)

            signedTx, err := transactor.Signer(signer.Address(), testTx)
            Nil(t.T(), err)

            err = testDB.StoreEthTx(t.GetTestContext(), signedTx, chainID, common.BigToHash(big.NewInt(5)), uint64(i), gofakeit.Uint64())
            Nil(t.T(), err)
        }

        // For testing, have the same txhash for all unconfirmed blocks.
        for i := confirmedBlockHeight + 1; i <= headBlock; i++ {
            testTx := types.NewTx(&types.LegacyTx{
                Nonce:    uint64(0),
                GasPrice: new(big.Int).SetUint64(gofakeit.Uint64()),
                Gas:      gofakeit.Uint64(),
                To:       addressPtr(common.BigToAddress(new(big.Int).SetUint64(gofakeit.Uint64()))),
                Value:    new(big.Int).SetUint64(gofakeit.Uint64()),
                Data:     []byte(gofakeit.Paragraph(1, 2, 3, " ")),
            })
            transactor, err := localsigner.NewSigner(testWallet.PrivateKey()).GetTransactor(t.GetTestContext(), testTx.ChainId())
            Nil(t.T(), err)

            signedTx, err := transactor.Signer(signer.Address(), testTx)
            Nil(t.T(), err)

            err = testDB.StoreEthTxAtHead(t.GetTestContext(), signedTx, chainID, common.BigToHash(big.NewInt(5)), uint64(i), gofakeit.Uint64())
            Nil(t.T(), err)
        }

        txFilter := db.EthTxFilter{
            ChainID: chainID,
        }
        txs, err := testDB.RetrieveUnconfirmedEthTxsFromHeadRangeQuery(t.GetTestContext(), txFilter, 0, headBlock, lastIndexed, 1)
        Nil(t.T(), err)
        Equal(t.T(), 100, len(txs))
        if len(txs) == 100 {
            Equal(t.T(), uint64(0), txs[0].Tx.Nonce())
            // Check block range
            Equal(t.T(), uint64(110), txs[0].BlockNumber)
            Equal(t.T(), uint64(11), txs[99].BlockNumber)
            // check threshold of confirmed vs unconfirmed
            Equal(t.T(), uint64(1), txs[10].Tx.Nonce())
            Equal(t.T(), uint64(0), txs[9].Tx.Nonce())
        }
        txs, err = testDB.RetrieveUnconfirmedEthTxsFromHeadRangeQuery(t.GetTestContext(), txFilter, 0, headBlock, lastIndexed, 2)
        Nil(t.T(), err)

        Equal(t.T(), 10, len(txs))
        if len(txs) == 10 {
            // Check that these are confirmed logs
            Equal(t.T(), uint64(1), txs[0].Tx.Nonce())
        }
    })
}

func (t *DBSuite) TestUnconfirmedRecieptQuery() {
    t.RunOnAllDBs(func(testDB db.EventDB) {
        chainID := gofakeit.Uint32()
        contractAddress := common.BigToAddress(big.NewInt(gofakeit.Int64()))
        const confirmedBlockHeight = 100
        const headBlock = 110
        for i := 1; i <= confirmedBlockHeight; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))
            receipt := t.MakeRandomReceipt(txHash)
            receipt.BlockNumber = big.NewInt(int64(i))
            receipt.ContractAddress = contractAddress
            // For testing, all confirmed receipts will have a status of 1
            receipt.Status = 1
            err := testDB.StoreReceipt(t.GetTestContext(), chainID, receipt)
            Nil(t.T(), err)
        }
        err := testDB.StoreLastIndexed(t.GetTestContext(), contractAddress, chainID, confirmedBlockHeight, scribeTypes.IndexingConfirmed)
        Nil(t.T(), err)

        // For testing, having the same txhash for all unconfirmed blocks.
        for i := confirmedBlockHeight + 1; i <= headBlock; i++ {
            txHash := common.BigToHash(big.NewInt(gofakeit.Int64()))

            receipt := t.MakeRandomReceipt(txHash)
            receipt.BlockNumber = big.NewInt(int64(i))
            receipt.ContractAddress = contractAddress
            // For testing, all confirmed receipts will have a status of 1
            receipt.Status = 0
            err := testDB.StoreReceiptAtHead(t.GetTestContext(), chainID, receipt)
            Nil(t.T(), err)
        }

        receiptFilter := db.ReceiptFilter{
            ChainID:         chainID,
            ContractAddress: contractAddress.String(),
        }
        receipts, err := testDB.RetrieveReceiptsFromHeadRangeQuery(t.GetTestContext(), receiptFilter, 0, headBlock, 1)
        Nil(t.T(), err)
        Equal(t.T(), 100, len(receipts))
        if len(receipts) == 100 {
            Equal(t.T(), uint64(0), receipts[0].Status)
            // Check block range
            Equal(t.T(), uint64(110), receipts[0].BlockNumber.Uint64())
            Equal(t.T(), uint64(11), receipts[99].BlockNumber.Uint64())
            // check threshold of confirmed vs unconfirmed
            Equal(t.T(), uint64(1), receipts[10].Status)
            Equal(t.T(), uint64(0), receipts[9].Status)
        }
        receipts, err = testDB.RetrieveReceiptsFromHeadRangeQuery(t.GetTestContext(), receiptFilter, 0, headBlock, 2)
        Nil(t.T(), err)

        Equal(t.T(), 10, len(receipts))
        if len(receipts) == 10 {
            // Check that these are confirmed logs
            Equal(t.T(), uint64(1), receipts[0].Status)
        }
    })
}