github.com/iotexproject/iotex-core@v1.14.1-rc1/blockindex/sgd_indexer_test.go (about)

     1  package blockindex
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"math/big"
     7  	"strconv"
     8  	"sync/atomic"
     9  	"testing"
    10  
    11  	"github.com/iotexproject/go-pkgs/hash"
    12  	"github.com/iotexproject/iotex-address/address"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/iotexproject/iotex-core/action"
    16  	"github.com/iotexproject/iotex-core/blockchain/block"
    17  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    18  	"github.com/iotexproject/iotex-core/db"
    19  	"github.com/iotexproject/iotex-core/db/batch"
    20  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    21  	"github.com/iotexproject/iotex-core/state"
    22  	"github.com/iotexproject/iotex-core/test/identityset"
    23  	"github.com/iotexproject/iotex-core/testutil"
    24  )
    25  
    26  const (
    27  	_testSGDContractAddress = "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms"
    28  )
    29  
    30  func TestNewSGDRegistry(t *testing.T) {
    31  	r := require.New(t)
    32  
    33  	t.Run("kvStore is nil", func(t *testing.T) {
    34  		r.Panics(func() {
    35  			NewSGDRegistry(_testSGDContractAddress, 0, nil)
    36  		})
    37  	})
    38  
    39  	t.Run("invalid contract address", func(t *testing.T) {
    40  		kvStore := db.NewMemKVStore()
    41  		r.Panics(func() {
    42  			NewSGDRegistry("invalid contract", 0, kvStore)
    43  		})
    44  	})
    45  
    46  	t.Run("valid", func(t *testing.T) {
    47  		testDBPath, err := testutil.PathOfTempFile("sgd")
    48  		r.NoError(err)
    49  		ctx := context.Background()
    50  		cfg := db.DefaultConfig
    51  		cfg.DbPath = testDBPath
    52  		kvStore := db.NewBoltDB(cfg)
    53  		sgdRegistry := NewSGDRegistry(_testSGDContractAddress, 0, kvStore)
    54  		r.NoError(sgdRegistry.Start(ctx))
    55  		defer func() {
    56  			r.NoError(sgdRegistry.Stop(ctx))
    57  			testutil.CleanupPath(testDBPath)
    58  		}()
    59  
    60  		nonce := uint64(0)
    61  		r.Equal(nonce, sgdRegistry.StartHeight())
    62  		hh, err := sgdRegistry.Height()
    63  		r.NoError(err)
    64  		r.Equal(nonce, hh)
    65  		registerAddress, err := address.FromHex("5b38da6a701c568545dcfcb03fcb875f56beddc4")
    66  		r.NoError(err)
    67  		receiverAddress, err := address.FromHex("78731d3ca6b7e34ac0f824c42a7cc18a495cabab")
    68  		r.NoError(err)
    69  		t.Run("registerContract", func(t *testing.T) {
    70  			builder := block.NewTestingBuilder()
    71  			event := _sgdABI.Events["ContractRegistered"]
    72  			data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab")
    73  			exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
    74  			r.NoError(err)
    75  			h, _ := exec.Hash()
    76  			logs := &action.Log{
    77  				Address: _testSGDContractAddress,
    78  				Topics:  []hash.Hash256{hash.Hash256(event.ID)},
    79  				Data:    data,
    80  			}
    81  			blk := createTestingBlock(builder, 1, h, exec, logs)
    82  			r.NoError(sgdRegistry.PutBlock(ctx, blk))
    83  			receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String(), 1)
    84  			r.NoError(err)
    85  			r.Equal(_sgdPercentage, percentage)
    86  			r.Equal(receiverAddress, receiver)
    87  			r.False(isApproved)
    88  
    89  			lists, err := sgdRegistry.FetchContracts(ctx, 1)
    90  			r.NoError(err)
    91  			r.Equal(1, len(lists))
    92  			r.Equal(registerAddress.Bytes(), lists[0].Contract.Bytes())
    93  			r.Equal(receiverAddress.Bytes(), lists[0].Receiver.Bytes())
    94  			r.False(lists[0].Approved)
    95  		})
    96  		t.Run("approveContract", func(t *testing.T) {
    97  			builder := block.NewTestingBuilder()
    98  			event := _sgdABI.Events["ContractApproved"]
    99  			data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4")
   100  			exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
   101  			r.NoError(err)
   102  			h, _ := exec.Hash()
   103  			logs := &action.Log{
   104  				Address: _testSGDContractAddress,
   105  				Topics:  []hash.Hash256{hash.Hash256(event.ID)},
   106  				Data:    data,
   107  			}
   108  			blk := createTestingBlock(builder, 2, h, exec, logs)
   109  			r.NoError(sgdRegistry.PutBlock(ctx, blk))
   110  			receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String(), 2)
   111  			r.NoError(err)
   112  			r.Equal(receiverAddress, receiver)
   113  			r.True(isApproved)
   114  			r.Equal(_sgdPercentage, percentage)
   115  		})
   116  		t.Run("disapproveContract", func(t *testing.T) {
   117  			builder := block.NewTestingBuilder()
   118  			event := _sgdABI.Events["ContractDisapproved"]
   119  			data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4")
   120  			exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
   121  			r.NoError(err)
   122  			h, _ := exec.Hash()
   123  			logs := &action.Log{
   124  				Address: _testSGDContractAddress,
   125  				Topics:  []hash.Hash256{hash.Hash256(event.ID)},
   126  				Data:    data,
   127  			}
   128  			blk := createTestingBlock(builder, 3, h, exec, logs)
   129  			r.NoError(sgdRegistry.PutBlock(ctx, blk))
   130  			receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String(), 3)
   131  			r.NoError(err)
   132  			r.Equal(receiverAddress, receiver)
   133  			r.False(isApproved)
   134  			r.Equal(_sgdPercentage, percentage)
   135  		})
   136  		t.Run("removeContract", func(t *testing.T) {
   137  			builder := block.NewTestingBuilder()
   138  			event := _sgdABI.Events["ContractRemoved"]
   139  			data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4")
   140  			exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
   141  			r.NoError(err)
   142  			h, _ := exec.Hash()
   143  			logs := &action.Log{
   144  				Address: _testSGDContractAddress,
   145  				Topics:  []hash.Hash256{hash.Hash256(event.ID)},
   146  				Data:    data,
   147  			}
   148  			blk := createTestingBlock(builder, 4, h, exec, logs)
   149  			r.NoError(sgdRegistry.PutBlock(ctx, blk))
   150  			receiver, percentage, isApproved, err := sgdRegistry.CheckContract(ctx, registerAddress.String(), 4)
   151  			r.NoError(err)
   152  			r.Nil(receiver)
   153  			r.False(isApproved)
   154  			hh, err := sgdRegistry.Height()
   155  			r.NoError(err)
   156  			r.Equal(blk.Height(), hh)
   157  			r.Equal(uint64(0), percentage)
   158  
   159  			_, err = sgdRegistry.FetchContracts(ctx, blk.Height())
   160  			r.ErrorIs(err, state.ErrStateNotExist)
   161  		})
   162  	})
   163  	t.Run("heightRestriction", func(t *testing.T) {
   164  		cases := []struct {
   165  			startHeight uint64
   166  			height      uint64
   167  			readHeight  uint64
   168  			valid       bool
   169  		}{
   170  			{0, 0, 0, true},
   171  			{0, 0, 1, false},
   172  			{0, 2, 0, true},
   173  			{0, 2, 1, false},
   174  			{0, 2, 2, true},
   175  			{0, 2, 3, false},
   176  			{10, 0, 0, true},
   177  			{10, 0, 1, true},
   178  			{10, 0, 9, true},
   179  			{10, 0, 10, false},
   180  			{10, 0, 11, false},
   181  			{10, 10, 0, true},
   182  			{10, 10, 1, true},
   183  			{10, 10, 9, true},
   184  			{10, 10, 10, true},
   185  			{10, 10, 11, false},
   186  		}
   187  		for i := range cases {
   188  			name := strconv.FormatInt(int64(i), 10)
   189  			t.Run(name, func(t *testing.T) {
   190  				testDBPath, err := testutil.PathOfTempFile("sgd")
   191  				r.NoError(err)
   192  				ctx := context.Background()
   193  				cfg := db.DefaultConfig
   194  				cfg.DbPath = testDBPath
   195  				kvStore := db.NewBoltDB(cfg)
   196  				sgdRegistry := &sgdRegistry{
   197  					contract:    _testSGDContractAddress,
   198  					startHeight: cases[i].startHeight,
   199  					kvStore:     kvStore,
   200  				}
   201  				r.NoError(sgdRegistry.Start(ctx))
   202  				defer func() {
   203  					r.NoError(sgdRegistry.Stop(ctx))
   204  					testutil.CleanupPath(testDBPath)
   205  				}()
   206  				// register
   207  				nonce := uint64(0)
   208  				registerAddress, err := address.FromHex("5b38da6a701c568545dcfcb03fcb875f56beddc4")
   209  				r.NoError(err)
   210  				builder := block.NewTestingBuilder()
   211  				event := _sgdABI.Events["ContractRegistered"]
   212  				data, _ := hex.DecodeString("0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc400000000000000000000000078731d3ca6b7e34ac0f824c42a7cc18a495cabab")
   213  				exec, err := action.SignedExecution(_testSGDContractAddress, identityset.PrivateKey(27), atomic.AddUint64(&nonce, 1), big.NewInt(0), 10000000, big.NewInt(9000000000000), data)
   214  				r.NoError(err)
   215  				h, _ := exec.Hash()
   216  				logs := &action.Log{
   217  					Address: _testSGDContractAddress,
   218  					Topics:  []hash.Hash256{hash.Hash256(event.ID)},
   219  					Data:    data,
   220  				}
   221  				expectHeight, err := sgdRegistry.expectHeight()
   222  				r.NoError(err)
   223  				blk := createTestingBlock(builder, expectHeight, h, exec, logs)
   224  				r.NoError(sgdRegistry.PutBlock(ctx, blk))
   225  				_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), 1)
   226  				r.NoError(err)
   227  				// update height
   228  				b := batch.NewBatch()
   229  				b.Put(_sgdToHeightNS, _sgdCurrentHeight, byteutil.Uint64ToBytesBigEndian(cases[i].height), "failed to put current height")
   230  				sgdRegistry.kvStore.WriteBatch(b)
   231  				// check
   232  				if !cases[i].valid {
   233  					_, err = sgdRegistry.FetchContracts(ctx, cases[i].readHeight)
   234  					r.ErrorContains(err, "invalid height")
   235  					_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].readHeight)
   236  					r.ErrorContains(err, "invalid height")
   237  				} else {
   238  					_, err = sgdRegistry.FetchContracts(ctx, cases[i].readHeight)
   239  					r.Nil(err)
   240  					_, _, _, err = sgdRegistry.CheckContract(ctx, registerAddress.String(), cases[i].readHeight)
   241  					r.Nil(err)
   242  				}
   243  			})
   244  		}
   245  	})
   246  }
   247  
   248  func createTestingBlock(builder *block.TestingBuilder, height uint64, h hash.Hash256, act *action.SealedEnvelope, logs *action.Log) *block.Block {
   249  	block.LoadGenesisHash(&genesis.Default)
   250  	r := &action.Receipt{
   251  		Status:      1,
   252  		BlockHeight: height,
   253  		ActionHash:  h,
   254  	}
   255  
   256  	blk, _ := builder.
   257  		SetHeight(height).
   258  		SetPrevBlockHash(h).
   259  		AddActions(act).
   260  		SetReceipts([]*action.Receipt{
   261  			r.AddLogs(logs),
   262  		}).
   263  		SetTimeStamp(testutil.TimestampNow().UTC()).
   264  		SignAndBuild(identityset.PrivateKey(27))
   265  	return &blk
   266  }