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