Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change paradigm from checking for missing childrent to keeping track of tip via electrs #369

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion database/bfgd/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ type Database interface {
BtcBlockInsert(ctx context.Context, bb *BtcBlock) error
BtcBlockByHash(ctx context.Context, hash [32]byte) (*BtcBlock, error)
BtcBlockHeightByHash(ctx context.Context, hash [32]byte) (uint64, error)
BtcBlocksHeightsWithNoChildren(ctx context.Context) ([]uint64, error)

// Pop data
PopBasisByL2KeystoneAbrevHash(ctx context.Context, aHash [32]byte, excludeUnconfirmed bool, page uint32) ([]PopBasis, error)
Expand Down
162 changes: 0 additions & 162 deletions database/bfgd/database_ext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1752,168 +1752,6 @@ func TestL2BtcFinalitiesByL2KeystoneNotPublishedHeight(t *testing.T) {
}
}

func TestBtcHeightsNoChildren(t *testing.T) {
type testTableItem struct {
name string
numberToCreateWithChildren int
numberToCreateWithNoChildren int
overlapCount int
}

testTable := []testTableItem{
{
name: "0",
numberToCreateWithNoChildren: 0,
numberToCreateWithChildren: 43,
},
{
name: "less than 100",
numberToCreateWithNoChildren: 76,
numberToCreateWithChildren: 4,
},
{
name: "more than 100",
numberToCreateWithNoChildren: 126,
numberToCreateWithChildren: 333,
},
{
name: "more than 100 and overlap",
numberToCreateWithNoChildren: 126,
numberToCreateWithChildren: 333,
overlapCount: 98,
},
}

createBlocksWithNoChildren := func(ctx context.Context, count int, db bfgd.Database) []int64 {
heights := make([]int64, count)
for i := range count {
height := mathrand.Int64()
hash := make([]byte, 32)
if _, err := rand.Read(hash); err != nil {
t.Fatal(err)
}
header := make([]byte, 80)
if _, err := rand.Read(header); err != nil {
t.Fatal(err)
}

btcBlock := bfgd.BtcBlock{
Height: uint64(height),
Hash: hash,
Header: header,
}

if err := db.BtcBlockInsert(ctx, &btcBlock); err != nil {
t.Fatal(err)
}

heights[i] = height
}

return heights
}

createBlocksWithChildren := func(ctx context.Context, count int, db bfgd.Database, avoidHeights []int64, overlapHeights []int64) []int64 {
var prevHash []byte
overlapHeightI := 0
heights := make([]int64, count)
for i := range count {
var height int64
for {
if overlapHeightI < len(overlapHeights) {
height = overlapHeights[overlapHeightI]
overlapHeightI++
break
}

height = mathrand.Int64()
if !slices.Contains(avoidHeights, height) {
break
}
}
hash := make([]byte, 32)
if _, err := rand.Read(hash); err != nil {
t.Fatal(err)
}
header := make([]byte, 80)
if _, err := rand.Read(header); err != nil {
t.Fatal(err)
}

if len(prevHash) > 0 {
for k := range 32 {
header[k+4] = prevHash[k]
}
}

btcBlock := bfgd.BtcBlock{
Height: uint64(height),
Hash: hash,
Header: header,
}

if err := db.BtcBlockInsert(ctx, &btcBlock); err != nil {
t.Fatal(err)
}
prevHash = hash
heights[i] = height
}
return heights
}

for _, tti := range testTable {
t.Run(tti.name, func(t *testing.T) {
ctx, cancel := defaultTestContext()
defer cancel()

db, sdb, cleanup := createTestDB(ctx, t)
defer func() {
db.Close()
sdb.Close()
cleanup()
}()

var overlapHeights []int64
noChildrenHeights := createBlocksWithNoChildren(ctx, tti.numberToCreateWithNoChildren, db)

childrenHeights := createBlocksWithChildren(ctx, tti.numberToCreateWithChildren, db, nil, overlapHeights)

if tti.overlapCount > 0 {
overlapHeights = noChildrenHeights[:tti.overlapCount]
oldChildrenHeights := childrenHeights
for _, o := range oldChildrenHeights {
if !slices.Contains(overlapHeights, o) {
childrenHeights = append(childrenHeights, o)
}
}
}

heights, err := db.BtcBlocksHeightsWithNoChildren(ctx)
if err != nil {
t.Fatal(err)
}

toCmp := make([]uint64, len(noChildrenHeights)+1)
for i, c := range noChildrenHeights {
toCmp[i] = uint64(c)
}
toCmp[len(toCmp)-1] = uint64(childrenHeights[len(childrenHeights)-1])

slices.Sort(heights)
slices.Sort(toCmp)

// we return a nil slice if emtpy, change that here for deep.Equal
if len(heights) == 0 {
heights = []uint64{}
}

if diff := deep.Equal(toCmp[:len(toCmp)-1], heights); len(diff) != 0 {
t.Fatalf("unexpected diff %s", diff)
}
})
}
}

type BtcTransactionBroadcastRequest struct {
TxId string
SerializedTx []byte
Expand Down
51 changes: 0 additions & 51 deletions database/bfgd/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,57 +695,6 @@ func (p *pgdb) BtcBlockCanonicalHeight(ctx context.Context) (uint64, error) {
return result, nil
}

// BtcBlocksHeightsWithNoChildren returns the heights of blocks stored in the
// database that do not have any children, these represent possible forks that
// have not been handled yet.
func (p *pgdb) BtcBlocksHeightsWithNoChildren(ctx context.Context) ([]uint64, error) {
log.Tracef("BtcBlocksHeightsWithNoChildren")
defer log.Tracef("BtcBlocksHeightsWithNoChildren exit")

// Query all heights from btc_blocks where the block does not have any
// children and there are no other blocks at the same height with children.
// Excludes the tip because it will not have any children.
const q = `
SELECT height FROM btc_blocks bb1
WHERE NOT EXISTS (SELECT * FROM btc_blocks bb2 WHERE substr(bb2.header, 5, 32) = bb1.hash)
AND NOT EXISTS (
SELECT * FROM btc_blocks bb3 WHERE bb1.height = bb3.height
AND EXISTS (
SELECT * FROM btc_blocks bb4 WHERE substr(bb4.header, 5, 32) = bb3.hash
)
)
ORDER BY height DESC
OFFSET $1 + 1
LIMIT 100
`

var heights []uint64
for offset := 0; ; offset += 100 {
rows, err := p.db.QueryContext(ctx, q, offset)
if err != nil {
return nil, err
}
defer rows.Close()

startingLength := len(heights)
for rows.Next() {
var v uint64
if err := rows.Scan(&v); err != nil {
return nil, err
}
heights = append(heights, v)
}

if startingLength == len(heights) {
return heights, nil
}

if rows.Err() != nil {
return nil, rows.Err()
}
}
}

func (p *pgdb) refreshBTCBlocksCanonical(ctx context.Context) error {
// XXX this probably should be REFRESH MATERIALIZED VIEW CONCURRENTLY
// however, this is more testable at the moment and we're in a time crunch,
Expand Down
Loading
Loading