Skip to content
Merged
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
14 changes: 10 additions & 4 deletions tests/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -504,8 +504,10 @@ func induceReorg(ctx context.Context, env *testrunner.Env, _ []observer.TipSnaps
b1, b2 := bHashes[0], bHashes[1]

// 3. Wait for propagation: poll teranode-1's tip until == B2.
if err := waitForTeranodeTip(ctx, env.Teranode.RPC, b2, 30*time.Second); err != nil {
res.Err = fmt.Errorf("B2 propagation: %w", err)
// 60s timeout: SV→Teranode block propagation is generally reliable but
// can be slow under load. Without this succeeding the reorg cannot happen.
if err := waitForTeranodeTip(ctx, env.Teranode.RPC, b2, 60*time.Second); err != nil {
res.Err = fmt.Errorf("B2 did not propagate to teranode-1 within 60s — SV→Teranode block reception may be broken: %w", err)
return res
}

Expand All @@ -528,7 +530,11 @@ func induceReorg(ctx context.Context, env *testrunner.Env, _ []observer.TipSnaps
res.WinnerHash = c3

// 6. Wait for teranode-1 to reorg from B2 to C3.
deadline := time.Now().Add(60 * time.Second)
// 120s timeout: C3 is at height B0+3 vs B2 at B0+2; Teranode must receive
// all three C-chain blocks and activate the longer chain. Extended from 60s
// because Teranode has been observed to be slow to finalise reorgs under
// regtest conditions.
deadline := time.Now().Add(120 * time.Second)
for time.Now().Before(deadline) {
current, err := env.Teranode.RPC.GetBestBlockHash(ctx)
if err == nil && current == c3 {
Expand All @@ -543,6 +549,6 @@ func induceReorg(ctx context.Context, env *testrunner.Env, _ []observer.TipSnaps
case <-time.After(500 * time.Millisecond):
}
}
res.Err = fmt.Errorf("teranode-1 did not reorg to C3=%s within 60s", c3)
res.Err = fmt.Errorf("teranode-1 did not reorg to C3=%s within 120s", c3)
return res
}
12 changes: 12 additions & 0 deletions tests/inter2.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ func RunINTER2(ctx context.Context, env *testrunner.Env) (res testrunner.Result)
return res
}

// Verify the splitter propagated to svnode-1 before mining. If Teranode
// outbound legacy P2P is broken (teranode#942), the splitter never reaches
// svnode-1; the mined block would be empty; and all subsequent test txs
// spending the splitter's outputs would be rejected by both nodes.
splitterTxIDHex := hex.EncodeToString(splitter.TxID[:])
if err := waitForMempoolEntries(ctx, env.SVNode.RPC, []string{splitterTxIDHex}, 15*time.Second); err != nil {
return skipMissing(res, fmt.Sprintf(
"splitter tx not in svnode-1 mempool within 15s — Teranode outbound legacy P2P not propagating (teranode#942): %v",
err,
))
}

// Mine to confirm splitter; refresh funder UTXO state.
if _, err := mineBlocks(ctx, env, 1); err != nil {
return errorResult(res, err)
Expand Down
17 changes: 12 additions & 5 deletions tests/pc3.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,15 +290,22 @@ func parseStandardBlock(blockBytes []byte) ([]string, error) {
return nil, fmt.Errorf("block too short: %d bytes", len(blockBytes))
}
// Detect P2P wire frame by checking for any of the BSV network magic
// values at offset 0 (mainnet/testnet/regtest/STN). Teranode emits the
// mainnet magic regardless of network.
// values at offset 0. Teranode emits mainnet magic regardless of network.
//
// Magic bytes are written as uint32 little-endian (binary.Write LE) in
// p2p_probe.go. The expected on-wire byte order for each network is:
// mainnet 0xe8f3e1e3 → e3 e1 f3 e8
// regtest 0xfabfb5da → da b5 bf fa
// testnet 0xf4f3e5f4 → f4 e5 f3 f4
// teratestnet 0x0c09010d → 0d 01 09 0c
headerStart := 0
if len(blockBytes) >= 88 {
first4 := blockBytes[:4]
switch {
case first4[0] == 0xf9 && first4[1] == 0xbe && first4[2] == 0xb4 && first4[3] == 0xd9, // mainnet
first4[0] == 0xfa && first4[1] == 0xbf && first4[2] == 0xb5 && first4[3] == 0xda, // regtest
first4[0] == 0x0b && first4[1] == 0x11 && first4[2] == 0x09 && first4[3] == 0x07: // testnet
case first4[0] == 0xe3 && first4[1] == 0xe1 && first4[2] == 0xf3 && first4[3] == 0xe8, // BSV mainnet
first4[0] == 0xda && first4[1] == 0xb5 && first4[2] == 0xbf && first4[3] == 0xfa, // BSV regtest
first4[0] == 0xf4 && first4[1] == 0xe5 && first4[2] == 0xf3 && first4[3] == 0xf4, // BSV testnet
first4[0] == 0x0d && first4[1] == 0x01 && first4[2] == 0x09 && first4[3] == 0x0c: // BSV teratestnet
headerStart = 8 // skip 4 magic + 4 size
}
}
Expand Down
12 changes: 12 additions & 0 deletions tests/perf1.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ func RunPERF1(ctx context.Context, env *testrunner.Env) (res testrunner.Result)
}
return errorResult(res, fmt.Errorf("submit splitter @rate %d: %w", rate, submitErr))
}
// Verify the splitter propagated to svnode-1 before mining. If Teranode
// outbound legacy P2P is broken (teranode#942), the splitter never reaches
// svnode-1; the mined block would be empty; and all subsequent submissions
// would fail with missing-parent errors, causing an ERROR result.
splitterTxIDHex := hex.EncodeToString(splitter.TxID[:])
if propErr := waitForMempoolEntries(ctx, env.SVNode.RPC, []string{splitterTxIDHex}, 15*time.Second); propErr != nil {
return skipMissing(res, fmt.Sprintf(
"splitter tx not in svnode-1 mempool within 15s @rate=%d — Teranode outbound legacy P2P not propagating (teranode#942): %v",
rate, propErr,
))
}

if _, err := mineBlocks(ctx, env, 1); err != nil {
return errorResult(res, err)
}
Expand Down