From 58a3ab3832bac5c2a3675487d988f6ae27e704fe Mon Sep 17 00:00:00 2001 From: millken Date: Tue, 11 Jul 2023 04:01:14 +0800 Subject: [PATCH] [iip15] improve sgd indexer test coverage (#3893) --- blockindex/sgd_indexer_test.go | 179 ++++++++++++++++++++ e2etest/sgd_registry_test.go | 294 ++++++++++++++++++--------------- 2 files changed, 338 insertions(+), 135 deletions(-) create mode 100644 blockindex/sgd_indexer_test.go diff --git a/blockindex/sgd_indexer_test.go b/blockindex/sgd_indexer_test.go new file mode 100644 index 0000000000..7097f53588 --- /dev/null +++ b/blockindex/sgd_indexer_test.go @@ -0,0 +1,179 @@ +package blockindex + +import ( + "context" + "encoding/hex" + "math/big" + "sync/atomic" + "testing" + + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/action" + "github.com/iotexproject/iotex-core/blockchain/block" + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/state" + "github.com/iotexproject/iotex-core/test/identityset" + "github.com/iotexproject/iotex-core/testutil" + "github.com/stretchr/testify/require" +) + +const ( + _testSGDContractAddress = "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms" +) + +func TestNewSGDRegistry(t *testing.T) { + r := require.New(t) + + t.Run("kvStore is nil", func(t *testing.T) { + r.Panics(func() { + NewSGDRegistry(_testSGDContractAddress, 0, nil) + }) + }) + + t.Run("invalid contract address", func(t *testing.T) { + kvStore := db.NewMemKVStore() + r.Panics(func() { + NewSGDRegistry("invalid contract", 0, kvStore) + }) + }) + + t.Run("valid", func(t *testing.T) { + testDBPath, err := testutil.PathOfTempFile("sgd") + r.NoError(err) + ctx := context.Background() + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + sgdRegistry := NewSGDRegistry(_testSGDContractAddress, 0, kvStore) + r.NoError(sgdRegistry.Start(ctx)) + defer func() { + r.NoError(sgdRegistry.Stop(ctx)) + testutil.CleanupPath(testDBPath) + }() + + nonce := uint64(0) + r.Equal(nonce, sgdRegistry.StartHeight()) + hh, err := sgdRegistry.Height() + r.NoError(err) + r.Equal(nonce, hh) + registerAddress, err := address.FromHex("5b38da6a701c568545dcfcb03fcb875f56beddc4") + r.NoError(err) + receiverAddress, err := address.FromHex("78731d3ca6b7e34ac0f824c42a7cc18a495cabab") + r.NoError(err) + t.Run("registerContract", func(t *testing.T) { + builder := block.NewTestingBuilder() + event := _sgdABI.Events["ContractRegistered"] + data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab") + exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) + r.NoError(err) + h, _ := exec.Hash() + logs := &action.Log{ + Address: _testSGDContractAddress, + Topics: []hash.Hash256{hash.Hash256(event.ID)}, + Data: data, + } + blk := createTestingBlock(builder, 1, h, exec, logs) + r.NoError(sgdRegistry.PutBlock(ctx, blk)) + receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) + r.NoError(err) + r.Equal(_sgdPercentage, percentage) + r.Equal(receiverAddress, receiver) + r.False(isApproved) + + lists, err := sgdRegistry.FetchContracts(ctx) + r.NoError(err) + r.Equal(1, len(lists)) + r.Equal(registerAddress.Bytes(), lists[0].Contract.Bytes()) + r.Equal(receiverAddress.Bytes(), lists[0].Receiver.Bytes()) + r.False(lists[0].Approved) + }) + t.Run("approveContract", func(t *testing.T) { + builder := block.NewTestingBuilder() + event := _sgdABI.Events["ContractApproved"] + data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") + exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) + r.NoError(err) + h, _ := exec.Hash() + logs := &action.Log{ + Address: _testSGDContractAddress, + Topics: []hash.Hash256{hash.Hash256(event.ID)}, + Data: data, + } + blk := createTestingBlock(builder, 1, h, exec, logs) + r.NoError(sgdRegistry.PutBlock(ctx, blk)) + receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) + r.NoError(err) + r.Equal(receiverAddress, receiver) + r.True(isApproved) + r.Equal(_sgdPercentage, percentage) + }) + t.Run("disapproveContract", func(t *testing.T) { + builder := block.NewTestingBuilder() + event := _sgdABI.Events["ContractDisapproved"] + data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") + exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) + r.NoError(err) + h, _ := exec.Hash() + logs := &action.Log{ + Address: _testSGDContractAddress, + Topics: []hash.Hash256{hash.Hash256(event.ID)}, + Data: data, + } + blk := createTestingBlock(builder, 1, h, exec, logs) + r.NoError(sgdRegistry.PutBlock(ctx, blk)) + receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) + r.NoError(err) + r.Equal(receiverAddress, receiver) + r.False(isApproved) + r.Equal(_sgdPercentage, percentage) + }) + t.Run("removeContract", func(t *testing.T) { + builder := block.NewTestingBuilder() + event := _sgdABI.Events["ContractRemoved"] + data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") + exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) + r.NoError(err) + h, _ := exec.Hash() + logs := &action.Log{ + Address: _testSGDContractAddress, + Topics: []hash.Hash256{hash.Hash256(event.ID)}, + Data: data, + } + blk := createTestingBlock(builder, 2, h, exec, logs) + r.NoError(sgdRegistry.PutBlock(ctx, blk)) + receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) + r.ErrorContains(err, "not exist in DB") + r.Nil(receiver) + r.False(isApproved) + hh, err := sgdRegistry.Height() + r.NoError(err) + r.Equal(blk.Height(), hh) + r.Equal(uint64(0), percentage) + + _, err = sgdRegistry.FetchContracts(ctx) + r.ErrorIs(err, state.ErrStateNotExist) + }) + }) +} + +func createTestingBlock(builder *block.TestingBuilder, height uint64, h hash.Hash256, act action.SealedEnvelope, logs *action.Log) *block.Block { + block.LoadGenesisHash(&genesis.Default) + r := &action.Receipt{ + Status: 1, + BlockHeight: height, + ActionHash: h, + } + + blk, _ := builder. + SetHeight(height). + SetPrevBlockHash(h). + AddActions(act). + SetReceipts([]*action.Receipt{ + r.AddLogs(logs), + }). + SetTimeStamp(testutil.TimestampNow().UTC()). + SignAndBuild(identityset.PrivateKey(27)) + return &blk +} diff --git a/e2etest/sgd_registry_test.go b/e2etest/sgd_registry_test.go index a0b050978a..22c37f4486 100644 --- a/e2etest/sgd_registry_test.go +++ b/e2etest/sgd_registry_test.go @@ -25,12 +25,24 @@ import ( "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/config" "github.com/iotexproject/iotex-core/db" - "github.com/iotexproject/iotex-core/state" "github.com/iotexproject/iotex-core/state/factory" "github.com/iotexproject/iotex-core/testutil" "github.com/stretchr/testify/require" ) +type checkContractExpectation struct { + errorContains string + contractAddress string + expectPercentage uint64 + expectReceiver address.Address + expectIsApproved bool +} +type sgdTest struct { + name string + data []string + checkContractExpect checkContractExpectation +} + func TestSGDRegistry(t *testing.T) { r := require.New(t) ctx := context.Background() @@ -109,140 +121,152 @@ func TestSGDRegistry(t *testing.T) { receiverAddress, err := address.FromHex("78731d3ca6b7e34ac0f824c42a7cc18a495cabab") r.NoError(err) expectPercentage := uint64(30) - t.Run("registerContract", func(t *testing.T) { - data, _ = hex.DecodeString("d7e5fbf30000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab") - exec, err = action.SignedExecution(contractAddress, _execPriKey, atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) - r.NoError(err) - r.NoError(ap.Add(context.Background(), exec)) - blk, err = bc.MintNewBlock(fixedTime) - r.NoError(err) - r.NoError(bc.CommitBlock(blk)) - height, err = dao.Height() - r.NoError(err) - r.Equal(uint64(2), height) - - ctx = genesis.WithGenesisContext( - protocol.WithBlockchainCtx( - protocol.WithRegistry(ctx, registry), - protocol.BlockchainCtx{ - Tip: protocol.TipInfo{ - Height: height, - Hash: blk.HashHeader(), - Timestamp: blk.Timestamp(), - }, - }), - cfg.Genesis, - ) - r.NoError(sgdRegistry.PutBlock(ctx, blk)) - receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) - r.NoError(err) - r.Equal(expectPercentage, percentage) - r.Equal(receiverAddress, receiver) - r.False(isApproved) - - lists, err := sgdRegistry.FetchContracts(ctx) - r.NoError(err) - r.Equal(1, len(lists)) - r.Equal(registerAddress.Bytes(), lists[0].Contract.Bytes()) - r.Equal(receiverAddress.Bytes(), lists[0].Receiver.Bytes()) - r.False(lists[0].Approved) - }) - t.Run("approveContract", func(t *testing.T) { - data, _ = hex.DecodeString("07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") - exec, err = action.SignedExecution(contractAddress, _execPriKey, atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) - r.NoError(err) - r.NoError(ap.Add(context.Background(), exec)) - blk, err = bc.MintNewBlock(fixedTime) - r.NoError(err) - r.NoError(bc.CommitBlock(blk)) - height, err = dao.Height() - r.NoError(err) - r.Equal(uint64(3), height) - - ctx = genesis.WithGenesisContext( - protocol.WithBlockchainCtx( - protocol.WithRegistry(ctx, registry), - protocol.BlockchainCtx{ - Tip: protocol.TipInfo{ - Height: height, - Hash: blk.HashHeader(), - Timestamp: blk.Timestamp(), - }, - }), - cfg.Genesis, - ) - r.NoError(sgdRegistry.PutBlock(ctx, blk)) - receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) - r.NoError(err) - r.Equal(receiverAddress, receiver) - r.True(isApproved) - r.Equal(expectPercentage, percentage) - }) - - t.Run("disapproveContract", func(t *testing.T) { - data, _ = hex.DecodeString("a0ee93180000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") - exec, err = action.SignedExecution(contractAddress, _execPriKey, atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) - r.NoError(err) - r.NoError(ap.Add(context.Background(), exec)) - blk, err = bc.MintNewBlock(fixedTime) - r.NoError(err) - r.NoError(bc.CommitBlock(blk)) - height, err = dao.Height() - r.NoError(err) - r.Equal(uint64(4), height) - - ctx = genesis.WithGenesisContext( - protocol.WithBlockchainCtx( - protocol.WithRegistry(ctx, registry), - protocol.BlockchainCtx{ - Tip: protocol.TipInfo{ - Height: height, - Hash: blk.HashHeader(), - Timestamp: blk.Timestamp(), - }, - }), - cfg.Genesis, - ) - r.NoError(sgdRegistry.PutBlock(ctx, blk)) - receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) - r.NoError(err) - r.Equal(receiverAddress, receiver) - r.False(isApproved) - r.Equal(expectPercentage, percentage) - }) - - t.Run("removeContract", func(t *testing.T) { - data, _ = hex.DecodeString("c375c2ef0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4") - exec, err = action.SignedExecution(contractAddress, _execPriKey, atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) - r.NoError(err) - r.NoError(ap.Add(context.Background(), exec)) - blk, err = bc.MintNewBlock(fixedTime) - r.NoError(err) - r.NoError(bc.CommitBlock(blk)) - height, err = dao.Height() - r.NoError(err) - r.Equal(uint64(5), height) + tests := []sgdTest{ + { + name: "registerContract", + data: []string{ + "d7e5fbf30000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: false, + }, + }, + { + name: "approveContract", + data: []string{ + "07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: true, + }, + }, + { + name: "registerContractAgain", + data: []string{ + "d7e5fbf30000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: true, + }, + }, + { + name: "disapproveContract", + data: []string{ + "a0ee93180000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: false, + }, + }, + { + name: "removeContract", + data: []string{ + "c375c2ef0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + errorContains: "not exist in DB", + contractAddress: registerAddress.String(), + }, + }, + { + name: "approveNoneExistContract", + data: []string{ + "07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + errorContains: "not exist in DB", + contractAddress: registerAddress.String(), + }, + }, + { + name: "reAgainRegisterAndApproveContract", + data: []string{ + "d7e5fbf30000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab", + "07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: true, + }, + }, + { + name: "reDisApproveAndApproveContract", + data: []string{ + "a0ee93180000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + "a0ee93180000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + "07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + contractAddress: registerAddress.String(), + expectReceiver: receiverAddress, + expectPercentage: expectPercentage, + expectIsApproved: true, + }, + }, + { + name: "removeAndApproveContract", + data: []string{ + "c375c2ef0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + "07f7aafb0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4", + }, + checkContractExpect: checkContractExpectation{ + errorContains: "not exist in DB", + contractAddress: registerAddress.String(), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for i := 0; i < len(tt.data); i++ { + data, err := hex.DecodeString(tt.data[i]) + r.NoError(err) + exec, err = action.SignedExecution(contractAddress, _execPriKey, atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data) + r.NoError(err) + r.NoError(ap.Add(context.Background(), exec)) + blk, err = bc.MintNewBlock(fixedTime) + r.NoError(err) + r.NoError(bc.CommitBlock(blk)) + height, err = dao.Height() + r.NoError(err) + ctx = genesis.WithGenesisContext( + protocol.WithBlockchainCtx( + protocol.WithRegistry(ctx, registry), + protocol.BlockchainCtx{ + Tip: protocol.TipInfo{ + Height: height, + Hash: blk.HashHeader(), + Timestamp: blk.Timestamp(), + }, + }), + cfg.Genesis, + ) + r.NoError(sgdRegistry.PutBlock(ctx, blk)) + } + receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, tt.checkContractExpect.contractAddress) + if tt.checkContractExpect.errorContains != "" { + r.ErrorContains(err, tt.checkContractExpect.errorContains) + } else { + r.NoError(err) + } + r.Equal(tt.checkContractExpect.expectPercentage, percentage) + r.Equal(tt.checkContractExpect.expectReceiver, receiver) + r.Equal(tt.checkContractExpect.expectIsApproved, isApproved) - ctx = genesis.WithGenesisContext( - protocol.WithBlockchainCtx( - protocol.WithRegistry(ctx, registry), - protocol.BlockchainCtx{ - Tip: protocol.TipInfo{ - Height: height, - Hash: blk.HashHeader(), - Timestamp: blk.Timestamp(), - }, - }), - cfg.Genesis, - ) - r.NoError(sgdRegistry.PutBlock(ctx, blk)) - receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String()) - r.ErrorContains(err, "not exist in DB") - r.Nil(receiver) - r.False(isApproved) - r.Equal(uint64(0), percentage) + }) + } - _, err = sgdRegistry.FetchContracts(ctx) - r.ErrorIs(err, state.ErrStateNotExist) - }) }