go-blockchain/chain/p2psync_test.go
Virgil 5789325690 fix(blockchain): complete AX v0.8.0 polish pass
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 16:58:23 +00:00

140 lines
3.5 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"
"testing"
"dappco.re/go/core"
"dappco.re/go/core/blockchain/config"
store "dappco.re/go/core/store"
"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_P2PSync_EmptyChain_Ugly(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_P2PSync_ContextCancellation_Bad(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_P2PSync_NoBlockIDs_Good(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_P2PSync_RequestChainError_Bad(t *testing.T) {
s, err := store.New(":memory:")
require.NoError(t, err)
defer s.Close()
c := New(s)
mock := &mockP2PConn{
peerHeight: 10,
requestChainErr: core.E("", "connection reset", nil),
}
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_P2PSync_RequestObjectsError_Bad(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: core.E("", "timeout", nil),
}
opts := SyncOptions{Forks: config.TestnetForks}
err = c.P2PSync(context.Background(), mock, opts)
require.Error(t, err)
require.Contains(t, err.Error(), "request objects")
}