go-blockchain/chain/p2psync_test.go
Snider 34128d8e98
Some checks failed
Security Scan / security (pull_request) Successful in 11s
Test / Test (pull_request) Failing after 19s
refactor: migrate module path to dappco.re/go/core/blockchain
Update go.mod module line, all require/replace directives, and every
.go import path from forge.lthn.ai/core/go-blockchain to
dappco.re/go/core/blockchain. Add replace directives to bridge
dappco.re paths to existing forge.lthn.ai registry during migration.
Update CLAUDE.md, README, and docs to reflect the new module path.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 01:49:26 +00:00

140 lines
3.4 KiB
Go

// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2
package chain
import (
"context"
"fmt"
"testing"
store "dappco.re/go/core/store"
"dappco.re/go/core/blockchain/config"
"github.com/stretchr/testify/require"
)
// mockP2PConn implements P2PConnection for testing.
type mockP2PConn struct {
peerHeight uint64
// blocks maps hash -> (blockBlob, txBlobs)
blocks map[string]struct {
blockBlob []byte
txBlobs [][]byte
}
chainHashes [][]byte
// requestChainErr, if set, is returned by RequestChain.
requestChainErr error
// requestObjectsErr, if set, is returned by RequestObjects.
requestObjectsErr error
}
func (m *mockP2PConn) PeerHeight() uint64 { return m.peerHeight }
func (m *mockP2PConn) RequestChain(blockIDs [][]byte) (startHeight uint64, hashes [][]byte, err error) {
if m.requestChainErr != nil {
return 0, nil, m.requestChainErr
}
return 0, m.chainHashes, nil
}
func (m *mockP2PConn) RequestObjects(blockHashes [][]byte) ([]BlockBlobEntry, error) {
if m.requestObjectsErr != nil {
return nil, m.requestObjectsErr
}
var entries []BlockBlobEntry
for _, h := range blockHashes {
key := string(h)
if blk, ok := m.blocks[key]; ok {
entries = append(entries, BlockBlobEntry{
Block: blk.blockBlob,
Txs: blk.txBlobs,
})
}
}
return entries, nil
}
func TestP2PSync_EmptyChain(t *testing.T) {
// Test that P2PSync with a mock that has no blocks is a no-op.
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{peerHeight: 0}
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(context.Background(), mock, opts)
require.NoError(t, err)
}
func TestP2PSync_ContextCancellation(t *testing.T) {
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{peerHeight: 100} // claims 100 blocks but returns none
ctx, cancel := context.WithCancel(context.Background())
cancel() // cancel immediately
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(ctx, mock, opts)
require.ErrorIs(t, err, context.Canceled)
}
func TestP2PSync_NoBlockIDs(t *testing.T) {
// Peer claims a height but returns no block IDs from RequestChain.
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{
peerHeight: 10,
chainHashes: nil, // empty response
}
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(context.Background(), mock, opts)
require.NoError(t, err)
}
func TestP2PSync_RequestChainError(t *testing.T) {
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{
peerHeight: 10,
requestChainErr: fmt.Errorf("connection reset"),
}
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(context.Background(), mock, opts)
require.Error(t, err)
require.Contains(t, err.Error(), "request chain")
}
func TestP2PSync_RequestObjectsError(t *testing.T) {
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{
peerHeight: 10,
chainHashes: [][]byte{{0x01}},
requestObjectsErr: fmt.Errorf("timeout"),
}
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(context.Background(), mock, opts)
require.Error(t, err)
require.Contains(t, err.Error(), "request objects")
}