Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
13 changes: 11 additions & 2 deletions input/chainsync/chainsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ type ChainSyncStatus struct {
TipSlotNumber uint64
TipBlockHash string
TipReached bool
Era string
}

type StatusUpdateFunc func(ChainSyncStatus)
Expand Down Expand Up @@ -315,6 +316,7 @@ func (c *ChainSync) handleRollBackward(
hex.EncodeToString(point.Hash), // BlockHash
tip.Point.Slot, // TipSlotNumber
hex.EncodeToString(tip.Point.Hash), // TipBlockHash
"",
)
return nil
}
Expand All @@ -327,10 +329,12 @@ func (c *ChainSync) handleRollForward(
) error {
switch v := blockData.(type) {
case ledger.Block:
era := v.Header().Era().Name
evt := event.New("chainsync.block", time.Now(), NewBlockContext(v, c.networkMagic), NewBlockEvent(v, c.includeCbor))
c.eventChan <- evt
c.updateStatus(v.SlotNumber(), v.BlockNumber(), v.Hash(), tip.Point.Slot, hex.EncodeToString(tip.Point.Hash))
c.updateStatus(v.SlotNumber(), v.BlockNumber(), v.Hash(), tip.Point.Slot, hex.EncodeToString(tip.Point.Hash), era)
case ledger.BlockHeader:
era := v.Era().Name
blockSlot := v.SlotNumber()
blockHash, _ := hex.DecodeString(v.Hash())
block, err := c.oConn.BlockFetch().Client.GetBlock(ocommon.Point{Slot: blockSlot, Hash: blockHash})
Expand All @@ -354,7 +358,7 @@ func (c *ChainSync) handleRollForward(
NewTransactionEvent(block, transaction, c.includeCbor, resolvedInputs))
c.eventChan <- txEvt
}
c.updateStatus(v.SlotNumber(), v.BlockNumber(), v.Hash(), tip.Point.Slot, hex.EncodeToString(tip.Point.Hash))
c.updateStatus(v.SlotNumber(), v.BlockNumber(), v.Hash(), tip.Point.Slot, hex.EncodeToString(tip.Point.Hash), era)
}
return nil
}
Expand All @@ -364,6 +368,7 @@ func (c *ChainSync) handleBlockFetchBlock(
blockType uint,
block ledger.Block,
) error {
era := block.Header().Era().Name
blockEvt := event.New(
"chainsync.block",
time.Now(),
Expand Down Expand Up @@ -403,6 +408,7 @@ func (c *ChainSync) handleBlockFetchBlock(
block.Hash(),
c.bulkRangeEnd.Slot,
hex.EncodeToString(c.bulkRangeEnd.Hash),
era,
)
// Start normal chain-sync if we've reached the last block of our bulk range
if block.SlotNumber() == c.bulkRangeEnd.Slot {
Expand All @@ -419,7 +425,9 @@ func (c *ChainSync) updateStatus(
blockHash string,
tipSlotNumber uint64,
tipBlockHash string,
era string,
) {

// Update cursor cache
blockHashBytes, _ := hex.DecodeString(blockHash)
c.cursorCache = append(
Expand All @@ -444,6 +452,7 @@ func (c *ChainSync) updateStatus(
c.status.BlockHash = blockHash
c.status.TipSlotNumber = tipSlotNumber
c.status.TipBlockHash = tipBlockHash
c.status.Era = era
if c.statusUpdateFunc != nil {
c.statusUpdateFunc(*(c.status))
}
Expand Down
230 changes: 229 additions & 1 deletion input/chainsync/chainsync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,243 @@ package chainsync

import (
"encoding/hex"
"testing"
"time"

"testing"

"github.com/blinklabs-io/adder/event"
"github.com/blinklabs-io/gouroboros/connection"
"github.com/blinklabs-io/gouroboros/ledger"
"github.com/blinklabs-io/gouroboros/protocol/chainsync"
ocommon "github.com/blinklabs-io/gouroboros/protocol/common"
"github.com/stretchr/testify/assert"
utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano"
)

// MockAddr is a mock implementation of the net.Addr interface.
type MockAddr struct {
NetWorkStr string
AddrStr string
}

func (m MockAddr) Network() string {
return m.NetWorkStr
}

func (m MockAddr) String() string {
return m.AddrStr
}

// NewMockCallbackContext creates a mock CallbackContext for testing.
func NewMockCallbackContext() chainsync.CallbackContext {
return chainsync.CallbackContext{
ConnectionId: connection.ConnectionId{
LocalAddr: MockAddr{NetWorkStr: "tcp", AddrStr: "127.0.0.1:3000"},
RemoteAddr: MockAddr{NetWorkStr: "tcp", AddrStr: "127.0.0.1:4000"},
},
Client: nil,
Server: nil,
}
}

// MockBlock is a mock implementation of the ledger.Block interface for testing.
type MockBlock struct {
slotNumber uint64
blockNumber uint64
hash string
prevHash string
era ledger.Era
issuerVkey ledger.IssuerVkey
cbor []byte
}

func (m MockBlock) SlotNumber() uint64 {
return m.slotNumber
}

func (m MockBlock) BlockNumber() uint64 {
return m.blockNumber
}

func (m MockBlock) Hash() string {
return m.hash
}

func (m MockBlock) PrevHash() string {
return m.prevHash
}

func (m MockBlock) IssuerVkey() ledger.IssuerVkey {
return m.issuerVkey
}

func (m MockBlock) BlockBodySize() uint64 {
return 0
}

func (m MockBlock) Era() ledger.Era {
return m.era
}

func (m MockBlock) Cbor() []byte {
return m.cbor
}

func (m MockBlock) Header() ledger.BlockHeader {
return MockBlockHeader{
slotNumber: m.slotNumber,
blockNumber: m.blockNumber,
hash: m.hash,
prevHash: m.prevHash,
era: m.era,
issuerVkey: m.issuerVkey,
blockBodySize: 0,
cbor: m.cbor,
}
}

func (m MockBlock) Type() int {
return 0
}

func (m MockBlock) Transactions() []ledger.Transaction {
return nil
}

func (m MockBlock) Utxorpc() *utxorpc.Block {
return nil
}

// MockBlockHeader is a mock implementation of the ledger.BlockHeader interface for testing.
type MockBlockHeader struct {
slotNumber uint64
blockNumber uint64
hash string
prevHash string
era ledger.Era
issuerVkey ledger.IssuerVkey
blockBodySize uint64
cbor []byte
}

func (m MockBlockHeader) SlotNumber() uint64 {
return m.slotNumber
}

func (m MockBlockHeader) BlockNumber() uint64 {
return m.blockNumber
}

func (m MockBlockHeader) Hash() string {
return m.hash
}

func (m MockBlockHeader) PrevHash() string {
return m.prevHash
}

func (m MockBlockHeader) IssuerVkey() ledger.IssuerVkey {
return m.issuerVkey
}

func (m MockBlockHeader) BlockBodySize() uint64 {
return m.blockBodySize
}

func (m MockBlockHeader) Era() ledger.Era {
return m.era
}

func (m MockBlockHeader) Cbor() []byte {
return m.cbor
}

func TestEraUpdate(t *testing.T) {
// Create a new ChainSync instance
chainSync := New()

// Create a mock block with a specific era
mockEra := ledger.Era{Name: "MockEra"}
mockBlock := MockBlock{
slotNumber: 12345,
blockNumber: 67890,
hash: "mockHash",
prevHash: "mockPrevHash",
era: mockEra,
cbor: []byte("mockCbor"),
}

// Create a mock tip
mockTip := chainsync.Tip{
Point: ocommon.Point{
Slot: 12345,
Hash: []byte("mockTipHash"),
},
}

// Create a mock callback context
mockCallbackContext := NewMockCallbackContext()

// Call handleRollForward with the mock block, tip, and callback context
err := chainSync.handleRollForward(mockCallbackContext, 0, mockBlock, mockTip)
if err != nil {
t.Fatalf("handleRollForward failed: %v", err)
}

// Check if the era has been correctly updated in the status
if chainSync.status.Era != mockEra.Name {
t.Errorf("Expected era to be %s, got %s", mockEra.Name, chainSync.status.Era)
}

// Check if other status fields are correctly updated
if chainSync.status.SlotNumber != mockBlock.SlotNumber() {
t.Errorf("Expected slot number to be %d, got %d", mockBlock.SlotNumber(), chainSync.status.SlotNumber)
}

if chainSync.status.BlockNumber != mockBlock.BlockNumber() {
t.Errorf("Expected block number to be %d, got %d", mockBlock.BlockNumber(), chainSync.status.BlockNumber)
}

if chainSync.status.BlockHash != mockBlock.Hash() {
t.Errorf("Expected block hash to be %s, got %s", mockBlock.Hash(), chainSync.status.BlockHash)
}

if chainSync.status.TipSlotNumber != mockTip.Point.Slot {
t.Errorf("Expected tip slot number to be %d, got %d", mockTip.Point.Slot, chainSync.status.TipSlotNumber)
}

if chainSync.status.TipBlockHash != hex.EncodeToString(mockTip.Point.Hash) {
t.Errorf("Expected tip block hash to be %s, got %s", hex.EncodeToString(mockTip.Point.Hash), chainSync.status.TipBlockHash)
}
}

func TestUpdateStatusWithEra(t *testing.T) {
// Create a mock ChainSync object
chainSync := &ChainSync{
status: &ChainSyncStatus{},
statusUpdateFunc: func(status ChainSyncStatus) {
assert.Equal(t, "TestEra", status.Era, "Expected the Era field to be 'TestEra'")
},
}

// Call updateStatus with mock data including an era
chainSync.updateStatus(
100, // SlotNumber
1, // BlockNumber
"testHash", // BlockHash
100, // TipSlotNumber
"tipHash", // TipBlockHash
"TestEra", // Era
)

assert.Equal(t, uint64(100), chainSync.status.SlotNumber, "Expected SlotNumber to be 100")
assert.Equal(t, uint64(1), chainSync.status.BlockNumber, "Expected BlockNumber to be 1")
assert.Equal(t, "testHash", chainSync.status.BlockHash, "Expected BlockHash to be 'testHash'")
assert.Equal(t, uint64(100), chainSync.status.TipSlotNumber, "Expected TipSlotNumber to be 100")
assert.Equal(t, "tipHash", chainSync.status.TipBlockHash, "Expected TipBlockHash to be 'tipHash'")
assert.Equal(t, "TestEra", chainSync.status.Era, "Expected Era to be 'TestEra'")
}

func TestHandleRollBackward(t *testing.T) {
// Create a new ChainSync instance
c := &ChainSync{
Expand Down
Loading