2022-02-09 15:19:10 +00:00
|
|
|
package publisher
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/csv"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
2023-04-12 18:07:42 +00:00
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/shared/schema"
|
|
|
|
|
2022-06-15 07:21:26 +00:00
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
2022-02-09 15:19:10 +00:00
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
2023-03-31 15:39:27 +00:00
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/test_helpers"
|
2022-02-09 15:19:10 +00:00
|
|
|
|
2022-09-20 17:47:34 +00:00
|
|
|
fixt "github.com/cerc-io/ipld-eth-state-snapshot/fixture"
|
|
|
|
"github.com/cerc-io/ipld-eth-state-snapshot/test"
|
2022-02-09 15:19:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
pgConfig = test.DefaultPgConfig
|
|
|
|
nodeInfo = test.DefaultNodeInfo
|
|
|
|
// tables ordered according to fkey depedencies
|
2023-04-12 18:07:42 +00:00
|
|
|
allTables = []*schema.Table{
|
|
|
|
&schema.TableIPLDBlock,
|
|
|
|
&schema.TableNodeInfo,
|
|
|
|
&schema.TableHeader,
|
|
|
|
&schema.TableStateNode,
|
|
|
|
&schema.TableStorageNode,
|
2022-02-09 15:19:10 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func writeFiles(t *testing.T, dir string) *publisher {
|
|
|
|
pub, err := NewPublisher(dir, nodeInfo)
|
|
|
|
test.NoError(t, err)
|
2022-02-22 09:03:06 +00:00
|
|
|
test.NoError(t, pub.PublishHeader(&fixt.Block1_Header))
|
2022-02-09 15:19:10 +00:00
|
|
|
tx, err := pub.BeginTx()
|
|
|
|
test.NoError(t, err)
|
|
|
|
|
2023-05-10 18:11:12 +00:00
|
|
|
test.NoError(t, pub.PublishStateLeafNode(&fixt.Block1_StateNode0, tx))
|
2022-02-09 15:19:10 +00:00
|
|
|
|
|
|
|
test.NoError(t, tx.Commit())
|
|
|
|
return pub
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify that we can parse the csvs
|
|
|
|
// TODO check actual data
|
2023-04-12 18:07:42 +00:00
|
|
|
func verifyFileData(t *testing.T, path string, tbl *schema.Table) {
|
2022-02-09 15:19:10 +00:00
|
|
|
file, err := os.Open(path)
|
|
|
|
test.NoError(t, err)
|
|
|
|
r := csv.NewReader(file)
|
|
|
|
test.NoError(t, err)
|
|
|
|
r.FieldsPerRecord = len(tbl.Columns)
|
|
|
|
|
|
|
|
for {
|
|
|
|
_, err := r.Read()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
test.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWriting(t *testing.T) {
|
|
|
|
dir := t.TempDir()
|
|
|
|
// tempdir like /tmp/TempFoo/001/, TempFoo defaults to 0700
|
|
|
|
test.NoError(t, os.Chmod(filepath.Dir(dir), 0755))
|
|
|
|
|
|
|
|
pub := writeFiles(t, dir)
|
|
|
|
|
|
|
|
for _, tbl := range perBlockTables {
|
|
|
|
verifyFileData(t, TableFile(pub.dir, tbl.Name), tbl)
|
|
|
|
}
|
|
|
|
for i := uint32(0); i < pub.txCounter; i++ {
|
|
|
|
for _, tbl := range perNodeTables {
|
|
|
|
verifyFileData(t, TableFile(pub.txDir(i), tbl.Name), tbl)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: DB user requires role membership "pg_read_server_files"
|
|
|
|
func TestPgCopy(t *testing.T) {
|
|
|
|
test.NeedsDB(t)
|
|
|
|
|
|
|
|
dir := t.TempDir()
|
|
|
|
test.NoError(t, os.Chmod(filepath.Dir(dir), 0755))
|
|
|
|
pub := writeFiles(t, dir)
|
|
|
|
|
|
|
|
ctx := context.Background()
|
2022-06-15 07:21:26 +00:00
|
|
|
driver, err := postgres.NewSQLXDriver(ctx, pgConfig, nodeInfo)
|
2022-02-09 15:19:10 +00:00
|
|
|
test.NoError(t, err)
|
2023-03-31 15:39:27 +00:00
|
|
|
db := postgres.NewPostgresDB(driver, false)
|
2022-02-09 15:19:10 +00:00
|
|
|
|
2022-09-20 17:47:34 +00:00
|
|
|
test_helpers.TearDownDB(t, db)
|
2022-02-09 15:19:10 +00:00
|
|
|
|
|
|
|
// copy from files
|
|
|
|
pgCopyStatement := `COPY %s FROM '%s' CSV`
|
|
|
|
for _, tbl := range perBlockTables {
|
|
|
|
stm := fmt.Sprintf(pgCopyStatement, tbl.Name, TableFile(pub.dir, tbl.Name))
|
2022-06-15 07:21:26 +00:00
|
|
|
_, err = db.Exec(ctx, stm)
|
2022-02-09 15:19:10 +00:00
|
|
|
test.NoError(t, err)
|
|
|
|
}
|
|
|
|
for i := uint32(0); i < pub.txCounter; i++ {
|
|
|
|
for _, tbl := range perNodeTables {
|
|
|
|
stm := fmt.Sprintf(pgCopyStatement, tbl.Name, TableFile(pub.txDir(i), tbl.Name))
|
2022-06-15 07:21:26 +00:00
|
|
|
_, err = db.Exec(ctx, stm)
|
2022-02-09 15:19:10 +00:00
|
|
|
test.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check header was successfully committed
|
|
|
|
pgQueryHeader := `SELECT cid, block_hash
|
|
|
|
FROM eth.header_cids
|
|
|
|
WHERE block_number = $1`
|
|
|
|
type res struct {
|
|
|
|
CID string
|
|
|
|
BlockHash string
|
|
|
|
}
|
|
|
|
var header res
|
2022-06-15 07:21:26 +00:00
|
|
|
err = db.QueryRow(ctx, pgQueryHeader, fixt.Block1_Header.Number.Uint64()).Scan(
|
2022-02-09 15:19:10 +00:00
|
|
|
&header.CID, &header.BlockHash)
|
|
|
|
test.NoError(t, err)
|
|
|
|
|
2022-02-22 09:03:06 +00:00
|
|
|
headerNode, err := ipld.NewEthHeader(&fixt.Block1_Header)
|
2022-04-19 10:19:49 +00:00
|
|
|
test.NoError(t, err)
|
2022-02-09 15:19:10 +00:00
|
|
|
test.ExpectEqual(t, headerNode.Cid().String(), header.CID)
|
2022-02-22 09:03:06 +00:00
|
|
|
test.ExpectEqual(t, fixt.Block1_Header.Hash().String(), header.BlockHash)
|
2022-02-09 15:19:10 +00:00
|
|
|
}
|