From 58c1f13c3e4f6eebdd2145df6c66d76e5deb454b Mon Sep 17 00:00:00 2001 From: zhi Date: Fri, 18 Apr 2025 15:23:49 +0800 Subject: [PATCH 1/3] unit test for block preparer --- state/factory/blockpreparer_test.go | 107 ++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 state/factory/blockpreparer_test.go diff --git a/state/factory/blockpreparer_test.go b/state/factory/blockpreparer_test.go new file mode 100644 index 0000000000..2f31d2897f --- /dev/null +++ b/state/factory/blockpreparer_test.go @@ -0,0 +1,107 @@ +package factory + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-core/v2/action" + "github.com/iotexproject/iotex-core/v2/blockchain/block" + "github.com/iotexproject/iotex-core/v2/test/identityset" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" +) + +func TestBlockPreparer_PrepareOrWait(t *testing.T) { + preparer := newBlockPreparer() + prevHash := hash.Hash256b([]byte("previousHash")) + timestamp := time.Now() + mockBlk := &block.Block{} + called := false + + // Mock mint function + mintFn := func() (*block.Block, error) { + if called { + return nil, errors.New("block already minted") + } + return mockBlk, nil + } + mintFn2 := func() (*block.Block, error) { + return &block.Block{ + Body: block.Body{ + Actions: []*action.SealedEnvelope{}, + }, + }, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + wg := sync.WaitGroup{} + wg.Add(2) + go func() { + blk1, err := preparer.PrepareOrWait(ctx, prevHash[:], timestamp, mintFn) + require.NoError(t, err) + require.Equal(t, mockBlk, blk1) + wg.Done() + }() + go func() { + blk2, err := preparer.PrepareOrWait(ctx, prevHash[:], timestamp.Add(time.Second), mintFn2) + require.NoError(t, err) + require.NotEqual(t, mockBlk, blk2) + wg.Done() + }() + blk, err := preparer.PrepareOrWait(ctx, prevHash[:], timestamp, mintFn) + require.NoError(t, err) + require.Equal(t, mockBlk, blk) + wg.Wait() +} + +func TestBlockPreparer_PrepareOrWait_Timeout(t *testing.T) { + preparer := newBlockPreparer() + prevHash := hash.Hash256b([]byte("previousHash")) + timestamp := time.Now() + + // Mock mint function that takes too long + mintFn := func() (*block.Block, error) { + time.Sleep(2 * time.Second) + return &block.Block{}, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + blk, err := preparer.PrepareOrWait(ctx, prevHash[:], timestamp, mintFn) + require.Error(t, err) + require.Nil(t, blk) +} + +func TestBlockPreparer_ReceiveBlock(t *testing.T) { + preparer := newBlockPreparer() + prevHash := hash.Hash256b([]byte("previousHash")) + timestamp := time.Now() + + // Mock mint function + mintFn := func() (*block.Block, error) { + builder := &block.TestingBuilder{} + blk, err := builder.SetPrevBlockHash(prevHash).SignAndBuild(identityset.PrivateKey(0)) + return &blk, err + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + blk, err := preparer.PrepareOrWait(ctx, prevHash[:], timestamp, mintFn) + require.NoError(t, err) + + emptyblk := &block.Block{} + require.NoError(t, preparer.ReceiveBlock(emptyblk)) + _, ok := preparer.tasks[prevHash] + require.True(t, ok) + + require.NoError(t, preparer.ReceiveBlock(blk)) + _, ok = preparer.tasks[prevHash] + require.False(t, ok) +} From 2fd9e639324505ec204ef58f65482644dc5e8557 Mon Sep 17 00:00:00 2001 From: zhi Date: Wed, 23 Apr 2025 20:22:18 +0800 Subject: [PATCH 2/3] address comment --- state/factory/blockpreparer_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/state/factory/blockpreparer_test.go b/state/factory/blockpreparer_test.go index 2f31d2897f..c08aebb88e 100644 --- a/state/factory/blockpreparer_test.go +++ b/state/factory/blockpreparer_test.go @@ -26,6 +26,7 @@ func TestBlockPreparer_PrepareOrWait(t *testing.T) { if called { return nil, errors.New("block already minted") } + called = true return mockBlk, nil } mintFn2 := func() (*block.Block, error) { From be9cd7c1c27c4ec223db7c83df498a741d79e9d6 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 24 Apr 2025 11:00:36 +0800 Subject: [PATCH 3/3] cleanup blockpreparer --- state/factory/blockpreparer.go | 10 +++++++--- state/factory/blockpreparer_test.go | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/state/factory/blockpreparer.go b/state/factory/blockpreparer.go index 61399c40d0..e761e98afc 100644 --- a/state/factory/blockpreparer.go +++ b/state/factory/blockpreparer.go @@ -45,9 +45,12 @@ func (d *blockPreparer) PrepareOrWait(ctx context.Context, prevHash []byte, time } d.mu.Lock() - res := d.results[hash.Hash256(prevHash)][timestamp.UnixNano()] - d.mu.Unlock() - return res.blk, res.err + defer d.mu.Unlock() + if blks, ok := d.results[hash.BytesToHash256(prevHash)]; ok && blks[timestamp.UnixNano()] != nil { + res := blks[timestamp.UnixNano()] + return res.blk, res.err + } + return nil, errors.New("mint result not found") } func (d *blockPreparer) prepare(prevHash []byte, timestamp time.Time, mintFn func() (*block.Block, error)) chan struct{} { @@ -80,6 +83,7 @@ func (d *blockPreparer) prepare(prevHash []byte, timestamp time.Time, mintFn fun func (d *blockPreparer) ReceiveBlock(blk *block.Block) error { d.mu.Lock() delete(d.tasks, blk.PrevHash()) + delete(d.results, blk.PrevHash()) d.mu.Unlock() return nil } diff --git a/state/factory/blockpreparer_test.go b/state/factory/blockpreparer_test.go index c08aebb88e..a8106971fe 100644 --- a/state/factory/blockpreparer_test.go +++ b/state/factory/blockpreparer_test.go @@ -7,11 +7,12 @@ import ( "time" "github.com/iotexproject/go-pkgs/hash" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + "github.com/iotexproject/iotex-core/v2/action" "github.com/iotexproject/iotex-core/v2/blockchain/block" "github.com/iotexproject/iotex-core/v2/test/identityset" - "github.com/pkg/errors" - "github.com/stretchr/testify/require" ) func TestBlockPreparer_PrepareOrWait(t *testing.T) { @@ -101,8 +102,12 @@ func TestBlockPreparer_ReceiveBlock(t *testing.T) { require.NoError(t, preparer.ReceiveBlock(emptyblk)) _, ok := preparer.tasks[prevHash] require.True(t, ok) + _, ok = preparer.results[prevHash] + require.True(t, ok) require.NoError(t, preparer.ReceiveBlock(blk)) _, ok = preparer.tasks[prevHash] require.False(t, ok) + _, ok = preparer.results[prevHash] + require.False(t, ok) }