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 }