Files
lotus/lib/sqlite/sqlite_test.go
Aarsh Shah dcc903c65d feat: a new ChainIndexer to index tipsets, messages and events (#12421)
* chain index complete for msgs and txns

* dont need observer changes for now

* changes

* fix tests

* fix tests

* use th right context

* index empty tipsets correctly

* implement automated backfilling

* add event indexing and remove all old indices

* fix test

* revert deployment test changes

* revert test changes and better error handling for eth tx index lookups

* fix sql statments naming convention

* address review for Index GC

* more changes as per review

* changes as per review

* fix config

* mark events as reverted during reconciliation

* better reconciliation; pens down and code complete; also reconcile events

* fix tests

* improve config and docs

* improve docs and error handling

* improve read logic

* improve docs

* better logging and handle ennable event storage

* improve logs and index init proc

* better logging

* fix bugs based on calibnet testing

* create sqliite Indices

* gc should be based on epochs

* fix event query

* foreign keys should be enabled on the DB

* reverted tipsets should be removed as part of GC

* release read lock

* make it easy to backfill an empty index using reconciliation

* better docs for reconciliation

* fix conflicts with master

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix go mod

* fix formatting

* revert config changes

* address changes in observer

* remove top level chainindex package

* changes as per review

* changes as per review

* changes as per review

* handle index with reverted tipsets during reconciliation

* changes as per review

* fix type of max reconcile epoch

* changes to reconciliation as per review

* log ipld error

* better logging of progress

* disable chain indexer hydrate from snapshot based on config

* always populate index

* make config easy to reason about

* fix config

* fix messaging

* revert config changes

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* changes as per review

* make error messages homogenous

* fix indentation

* changes as per review

* feat: recompute tipset to generate missing events if event indexing is enabled (#12463)

* auto repair events

* make jen

* fix leaky abstraction

* better docs for gc retention epoch

* imrpove DB handling (#12485)

* fix conflict

* fix lite node config for indexer

* exclude reverted events from eth get logs if client queries by epoch

* Simply addressing for event lookups in the index.

simply addressing for event lookups

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix tests

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* feat: migration("re-indexing"), backfilling and diasgnostics tooling for the `ChainIndexer` (#12450)

* fix conflicts with chain indexer

* feat: chain indexer todos [skip changelog] (#12462)

* feat: finish todos of validation api

* feat: add indexed data verification with chain store

* feat: address comments and finish TODO

* fix: build issue

* address comments

* fix: ci issue

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* changes to Index Validation API based on Rodds first review

* build chain indexer API

* improve error handling

* feat: lotus-shed tooling for chain indexer (#12474)

* feat: add lotus-shed command for backfilling chain indexer

* feat: add lotus-shed command for inspecting the chain indexer

* feat: use single lotus-shed command to inspect and backfill

* fix: remove the unused queries

* small changes

* add change log

* backfilling improvements and fixes

* finish chain index validation and backfill tooling

* user documentation for the

* validate from epoch

* Apply suggestions from code review

Suggestions from Steve's read of the user doc.

Co-authored-by: Steve Loeppky <biglep@filoz.org>

* changes to user doc as per review

* Apply suggestions from code review

Co-authored-by: Steve Loeppky <biglep@filoz.org>

* changes to user doc as per review

* Apply suggestions from code review

Co-authored-by: Steve Loeppky <biglep@filoz.org>

* changes as per review

* feat: add event entries count in validation API (#12506)

* feat: add event entry count in validation API

* address comments

* use sqllite defaults (#12504)

* Apply suggestions from code review

Co-authored-by: Steve Loeppky <biglep@filoz.org>

* write chain index to a different dir

* Apply suggestions from code review

Co-authored-by: Steve Loeppky <biglep@filoz.org>

* fix conflicts

* UX improvements to backfilling

* feat: tests for the chain indexer (#12521)

* ddl tests

* tests for the chain indexer

* finish unit tests for chain indexer

* fix formatting

* cleanup reverted tipsets to avoid db bloat

* fix logging

* test for filter by address

* test gc cascade delete

* fix db locked error during backfilling

* fix var name

* increase db locked timeout

* fix db locked issue

* reduce db lock timeout

* no lock in gc

* reconcile does not need lock

* improved error handling

* Update chain-indexing-overview-for-rpc-providers.md

Doc updates based on @jennijuju feedack.

* Update chain-indexing-overview-for-rpc-providers.MD

Fixes after reviewing 33c1ca1831

* better metrics for backfilling

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update chain/index/chain-indexing-overview-for-rpc-providers.MD

Co-authored-by: Rod Vagg <rod@vagg.org>

* tests for changes to event addressing

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* changes as per review -> round 1

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* log tipset key cid

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix docs

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix tests

* fix tests

* make jen

* fix conflicts

---------

Co-authored-by: Aryan Tikarya <aryan.tikarya@dojima.network>
Co-authored-by: Rod Vagg <rod@vagg.org>
Co-authored-by: Steve Loeppky <biglep@filoz.org>

* fix lint

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* remove reverted flag from RPC

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix testing of events and dummy chain store

* remove lotus shed commands for old Indices

* change type of event counts to uint64

* only recompute events if theyre not found

* short-circuit empty events path for older tipsets

* chain indexer must be enabled if ETH RPC is enabled

* change name of message_id column to id in tipset_message table

* only expose SetRecomputeTipSetStateFunc

* dont block on head indexing for reading messages

* document why we're only checking for missing events for a single tipset

* document when we query for reverted events

* simplify event collection

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* fix test

* change event_id to id in the event table

* change head indexed timeout

* remove deprecated config options

* fail ETH RPC calls if ChainIndexer is disabled

* fix docs

* remove the tipset key cid func from lotus shed

* address review comments

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* chore(events): remove unnecessary DisableRealTimeFilterAPI (#12610)

* feat(cli): add --quiet to chainindex validate-backfill + cleanups (#12611)

* fix tests

* Apply suggestions from code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* error type for disabled chainindexer

* fix(chainindex): recompute tipset when we find no receipts

* fix(chainindexer): backfilling should halt when chain state data is missing and not backfill parents (#12619)

* fix backfilling UX

* Update chain/index/api.go

Co-authored-by: Rod Vagg <rod@vagg.org>

* address review

---------

Co-authored-by: Rod Vagg <rod@vagg.org>

* reduce log noise

* make jen

* make jen

* docs: finishing chain-indexer-overview-for-operators.md (#12600)

* Followup to PR #12450 for doc updates

This is being used to resolve the unresolved items in https://github.com/filecoin-project/lotus/pull/12450 since that PR is unwieldly at this point.

* Incorporated some items and added TODOs based on unresolved items from https://github.com/filecoin-project/lotus/pull/12450

* Incorporating more feedback

* Pointing to issue to learn about benefits

* Formatting fixes

* Apply most of the suggestions from @rvagg code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Incorporating feedback from https://github.com/filecoin-project/lotus/pull/12600#discussion_r1802519453

* Addressing https://github.com/filecoin-project/lotus/pull/12600#discussion_r1802540042 and more

* Moved chain-indexer docs to documentation
Renamed
Added ToC

We can move to lotus-docs later

* Update documentation/en/chain-indexer-overview-for-operators.md

Co-authored-by: Rod Vagg <rod@vagg.org>

* Update documentation/en/chain-indexer-overview-for-operators.md

Co-authored-by: Rod Vagg <rod@vagg.org>

* Added upgrade path when importing chain state from a snapshot.

* Typo fixes

* Update documentation/en/chain-indexer-overview-for-operators.md

Co-authored-by: Rod Vagg <rod@vagg.org>

* chore(doc): "regular checks" section for chainindexer docs (#12612)

* Apply suggestions from @rvagg code review

Co-authored-by: Rod Vagg <rod@vagg.org>

* Incorporating @aarshkshah1992 feedback

* Update documentation/en/chain-indexer-overview-for-operators.md

Co-authored-by: Rod Vagg <rod@vagg.org>

---------

Co-authored-by: Rod Vagg <rod@vagg.org>
Co-authored-by: Aarsh Shah <aarshkshah1992@gmail.com>

* remove go mod replace

* remove unnecessary changes from CHANGELOG

* fix test

* compare events AMT root (#12632)

* fix(chainindex): retry transaction if database connection is lost (#12657)

* retry database lost connection

* log context cancellation

* address review

* fix gateway itest: no chainindexer for lite nodes

* fix changelog

---------

Co-authored-by: Rod Vagg <rod@vagg.org>
Co-authored-by: Aryan Tikarya <aryan.tikarya@dojima.network>
Co-authored-by: Steve Loeppky <biglep@filoz.org>
2024-10-31 09:58:19 +00:00

240 lines
5.9 KiB
Go

package sqlite_test
import (
"context"
"database/sql"
"path/filepath"
"strings"
"testing"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/lotus/lib/sqlite"
)
func TestSqlite(t *testing.T) {
req := require.New(t)
ddl := []string{
`CREATE TABLE IF NOT EXISTS blip (
id INTEGER PRIMARY KEY AUTOINCREMENT,
blip_name TEXT NOT NULL
)`,
`CREATE TABLE IF NOT EXISTS bloop (
blip_id INTEGER NOT NULL,
bloop_name TEXT NOT NULL,
FOREIGN KEY (blip_id) REFERENCES blip(id)
)`,
`CREATE INDEX IF NOT EXISTS blip_name_index ON blip (blip_name)`,
}
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "/test.db")
db, err := sqlite.Open(dbPath)
req.NoError(err)
req.NotNil(db)
err = sqlite.InitDb(context.Background(), "testdb", db, ddl, nil)
req.NoError(err)
// insert some data
r, err := db.Exec("INSERT INTO blip (blip_name) VALUES ('blip1')")
req.NoError(err)
id, err := r.LastInsertId()
req.NoError(err)
req.Equal(int64(1), id)
_, err = db.Exec("INSERT INTO bloop (blip_id, bloop_name) VALUES (?, 'bloop1')", id)
req.NoError(err)
r, err = db.Exec("INSERT INTO blip (blip_name) VALUES ('blip2')")
req.NoError(err)
id, err = r.LastInsertId()
req.NoError(err)
req.Equal(int64(2), id)
_, err = db.Exec("INSERT INTO bloop (blip_id, bloop_name) VALUES (?, 'bloop2')", id)
req.NoError(err)
// check that the db contains what we think it should
expectedIndexes := []string{"blip_name_index"}
expectedData := []tabledata{
{
name: "_meta",
cols: []string{"version"},
data: [][]interface{}{
{int64(1)},
},
},
{
name: "blip",
cols: []string{"id", "blip_name"},
data: [][]interface{}{
{int64(1), "blip1"},
{int64(2), "blip2"},
},
},
{
name: "bloop",
cols: []string{"blip_id", "bloop_name"},
data: [][]interface{}{
{int64(1), "bloop1"},
{int64(2), "bloop2"},
},
},
}
actualIndexes, actualData := dumpTables(t, db)
req.Equal(expectedIndexes, actualIndexes)
req.Equal(expectedData, actualData)
req.NoError(db.Close())
// open again, check contents is the same
db, err = sqlite.Open(dbPath)
req.NoError(err)
req.NotNil(db)
err = sqlite.InitDb(context.Background(), "testdb", db, ddl, nil)
req.NoError(err)
// database should contain the same things
actualIndexes, actualData = dumpTables(t, db)
req.Equal(expectedIndexes, actualIndexes)
req.Equal(expectedData, actualData)
req.NoError(db.Close())
// open again, with a migration
db, err = sqlite.Open(dbPath)
req.NoError(err)
req.NotNil(db)
req.NotNil(db)
migration1 := func(ctx context.Context, tx *sql.Tx) error {
_, err := tx.Exec("ALTER TABLE blip ADD COLUMN blip_extra TEXT NOT NULL DEFAULT '!'")
return err
}
err = sqlite.InitDb(context.Background(), "testdb", db, ddl, []sqlite.MigrationFunc{migration1})
req.NoError(err)
// also add something new
r, err = db.Exec("INSERT INTO blip (blip_name, blip_extra) VALUES ('blip1', '!!!')")
req.NoError(err)
id, err = r.LastInsertId()
req.NoError(err)
_, err = db.Exec("INSERT INTO bloop (blip_id, bloop_name) VALUES (?, 'bloop3')", id)
req.NoError(err)
// database should contain new stuff
expectedData[0].data = append(expectedData[0].data, []interface{}{int64(2)}) // _meta schema version 2
expectedData[1] = tabledata{
name: "blip",
cols: []string{"id", "blip_name", "blip_extra"},
data: [][]interface{}{
{int64(1), "blip1", "!"},
{int64(2), "blip2", "!"},
{int64(3), "blip1", "!!!"},
},
}
expectedData[2].data = append(expectedData[2].data, []interface{}{int64(3), "bloop3"})
actualIndexes, actualData = dumpTables(t, db)
req.Equal(expectedIndexes, actualIndexes)
req.Equal(expectedData, actualData)
req.NoError(db.Close())
// open again, with another migration
db, err = sqlite.Open(dbPath)
req.NoError(err)
req.NotNil(db)
migration2 := func(ctx context.Context, tx *sql.Tx) error {
// add an index
_, err := tx.Exec("CREATE INDEX IF NOT EXISTS blip_extra_index ON blip (blip_extra)")
return err
}
err = sqlite.InitDb(context.Background(), "testdb", db, ddl, []sqlite.MigrationFunc{migration1, migration2})
req.NoError(err)
// database should contain new stuff
expectedData[0].data = append(expectedData[0].data, []interface{}{int64(3)}) // _meta schema version 3
expectedIndexes = append(expectedIndexes, "blip_extra_index")
actualIndexes, actualData = dumpTables(t, db)
req.Equal(expectedIndexes, actualIndexes)
req.Equal(expectedData, actualData)
req.NoError(db.Close())
}
func dumpTables(t *testing.T, db *sql.DB) ([]string, []tabledata) {
req := require.New(t)
var indexes []string
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='index'")
req.NoError(err)
for rows.Next() {
var name string
err = rows.Scan(&name)
req.NoError(err)
if !strings.Contains(name, "sqlite_autoindex") {
indexes = append(indexes, name)
}
}
var data []tabledata
rows, err = db.Query("SELECT name, sql FROM sqlite_master WHERE type = 'table'")
req.NoError(err)
for rows.Next() {
var name, sql string
err = rows.Scan(&name, &sql)
req.NoError(err)
if strings.HasPrefix(name, "sqlite") {
continue
}
sqla := strings.Split(sql, "\n")
cols := []string{}
for _, s := range sqla {
// alter table does funky things to the sql, hence the "," ReplaceAll:
s = strings.Split(strings.TrimSpace(strings.ReplaceAll(s, ",", "")), " ")[0]
switch s {
case "CREATE", "FOREIGN", "", ")":
default:
cols = append(cols, s)
}
}
data = append(data, tabledata{name: name, cols: cols})
rows2, err := db.Query("SELECT * FROM " + name)
req.NoError(err)
for rows2.Next() {
vals := make([]interface{}, len(cols))
vals2 := make([]interface{}, len(cols))
for i := range vals {
vals[i] = &vals2[i]
}
err = rows2.Scan(vals...)
req.NoError(err)
data[len(data)-1].data = append(data[len(data)-1].data, vals2)
}
}
return indexes, data
}
type tabledata struct {
name string
cols []string
data [][]interface{}
}