From 60c5e9ace04155335f46ce2634ab5f553f0dd020 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 18 Apr 2023 16:55:06 +0800 Subject: [PATCH 01/51] add system staking indexer interface --- blockindex/systemstaking_indexer.go | 60 +++++++++++++++++++++++++++++ chainservice/builder.go | 10 ++++- chainservice/chainservice.go | 13 ++++--- 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 blockindex/systemstaking_indexer.go diff --git a/blockindex/systemstaking_indexer.go b/blockindex/systemstaking_indexer.go new file mode 100644 index 0000000000..a3a0cd0cd1 --- /dev/null +++ b/blockindex/systemstaking_indexer.go @@ -0,0 +1,60 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "context" + "math/big" + + "github.com/iotexproject/iotex-core/action/protocol/staking" + "github.com/iotexproject/iotex-core/blockchain/block" + "github.com/iotexproject/iotex-core/blockchain/blockdao" +) + +type ( + // SystemStakingIndexer is the interface of system staking indexer + SystemStakingIndexer interface { + blockdao.BlockIndexer + + GetCandidateVotes(candidate string) (*big.Int, error) + GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) + } + + systemStakingIndexer struct{} +) + +// NewSystemStakingIndexer creates a new system staking indexer +func NewSystemStakingIndexer() SystemStakingIndexer { + return &systemStakingIndexer{} +} + +func (s *systemStakingIndexer) Start(ctx context.Context) error { + return nil +} + +func (s *systemStakingIndexer) Stop(ctx context.Context) error { + return nil +} + +func (s *systemStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { + return nil +} + +func (s *systemStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { + return nil +} + +func (s *systemStakingIndexer) Height() (uint64, error) { + return 0, nil +} + +func (s *systemStakingIndexer) GetCandidateVotes(candidate string) (*big.Int, error) { + return nil, nil +} + +func (s *systemStakingIndexer) GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) { + return nil, nil +} diff --git a/chainservice/builder.go b/chainservice/builder.go index ef44f1ce33..abe36233c6 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -240,13 +240,18 @@ func (builder *Builder) buildActionPool() error { return nil } +func (builder *Builder) buildSystemStakingIndexer() error { + builder.cs.systemStakingIndexer = blockindex.NewSystemStakingIndexer() + return nil +} + func (builder *Builder) buildBlockDAO(forTest bool) error { if builder.cs.blockdao != nil { return nil } var indexers []blockdao.BlockIndexer - indexers = append(indexers, builder.cs.factory) + indexers = append(indexers, builder.cs.factory, builder.cs.systemStakingIndexer) if !builder.cfg.Chain.EnableAsyncIndexWrite && builder.cs.indexer != nil { indexers = append(indexers, builder.cs.indexer) } @@ -619,6 +624,9 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) if err := builder.buildGatewayComponents(forTest); err != nil { return nil, err } + if err := builder.buildSystemStakingIndexer(); err != nil { + return nil, err + } if err := builder.buildBlockDAO(forTest); err != nil { return nil, err } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index fc41d3339d..badee49207 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -80,12 +80,13 @@ type ChainService struct { p2pAgent p2p.Agent electionCommittee committee.Committee // TODO: explorer dependency deleted at #1085, need to api related params - indexer blockindex.Indexer - bfIndexer blockindex.BloomFilterIndexer - candidateIndexer *poll.CandidateIndexer - candBucketsIndexer *staking.CandidatesBucketsIndexer - registry *protocol.Registry - nodeInfoManager *nodeinfo.InfoManager + indexer blockindex.Indexer + bfIndexer blockindex.BloomFilterIndexer + candidateIndexer *poll.CandidateIndexer + candBucketsIndexer *staking.CandidatesBucketsIndexer + registry *protocol.Registry + nodeInfoManager *nodeinfo.InfoManager + systemStakingIndexer blockindex.SystemStakingIndexer } // Start starts the server From d8b96d0d6e74a07499d012bb187f5a1cfd87ab62 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 21 Apr 2023 12:36:18 +0800 Subject: [PATCH 02/51] add handle event in liquid stake indexer --- blockindex/liquidstaking_indexer.go | 458 ++++++++++++++++++++++++++++ blockindex/systemstaking_indexer.go | 60 ---- chainservice/builder.go | 4 +- chainservice/chainservice.go | 2 +- e2etest/contract_test.go | 163 ++++++++++ 5 files changed, 624 insertions(+), 63 deletions(-) create mode 100644 blockindex/liquidstaking_indexer.go delete mode 100644 blockindex/systemstaking_indexer.go create mode 100644 e2etest/contract_test.go diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go new file mode 100644 index 0000000000..2c6cf24412 --- /dev/null +++ b/blockindex/liquidstaking_indexer.go @@ -0,0 +1,458 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "context" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/iotexproject/iotex-core/action" + "github.com/iotexproject/iotex-core/action/protocol/staking" + "github.com/iotexproject/iotex-core/blockchain/block" + "github.com/iotexproject/iotex-core/blockchain/blockdao" + "github.com/iotexproject/iotex-core/pkg/log" + "github.com/pkg/errors" + "go.uber.org/zap" +) + +const ( + // TODO (iip-13): replace with the real liquid staking contract address + LiquidStakingContractAddress = "" + + // TODO (iip-13): replace with the real liquid staking contract ABI + _liquidStakingContractABI = `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "x", + "type": "uint256" + } + ], + "name": "Set", + "type": "event" + }, + { + "inputs": [], + "name": "get", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "x", + "type": "uint256" + } + ], + "name": "set", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ]` +) + +type ( + // LiquidStakingIndexer is the interface of liquid staking indexer + LiquidStakingIndexer interface { + blockdao.BlockIndexer + + GetCandidateVotes(candidate string) (*big.Int, error) + GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) + } + + liquidStakingIndexer struct { + bucketMap map[uint64]*BucketInfo // map[token]bucketInfo + bucketTypes []*BucketType + bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + + blockInterval time.Duration + } + + // BucketInfo is the bucket information + BucketInfo struct { + TypeIndex uint64 + UnlockedAt *time.Time + UnstakedAt *time.Time + Delegate string + } + + // BucketType is the bucket type + BucketType struct { + Amount *big.Int + Duration time.Duration + ActivatedAt *time.Time + } + + eventParam map[string]any +) + +var ( + _liquidStakingInterface abi.ABI + + errUnpackEvent = errors.New("failed to unpack event") +) + +func init() { + var err error + _liquidStakingInterface, err = abi.JSON(strings.NewReader(_liquidStakingContractABI)) + if err != nil { + panic(err) + } +} + +// NewLiquidStakingIndexer creates a new liquid staking indexer +func NewLiquidStakingIndexer() *liquidStakingIndexer { + return &liquidStakingIndexer{} +} + +func (s *liquidStakingIndexer) Start(ctx context.Context) error { + return nil +} + +func (s *liquidStakingIndexer) Stop(ctx context.Context) error { + return nil +} + +func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { + for _, receipt := range blk.Receipts { + for _, log := range receipt.Logs() { + if log.Address != LiquidStakingContractAddress { + continue + } + if err := s.handleEvent(ctx, blk, log); err != nil { + return err + } + } + } + return nil +} + +func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { + return nil +} + +func (s *liquidStakingIndexer) Height() (uint64, error) { + return 0, nil +} + +func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) (*big.Int, error) { + return nil, nil +} + +func (s *liquidStakingIndexer) GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) { + return nil, nil +} + +func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block, log *action.Log) error { + // get event abi + abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) + if err != nil { + return errors.Wrapf(err, "get event abi from topic %v failed", log.Topics[0]) + } + // unpack event data + event := make(map[string]any) + if err = abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { + return errors.Wrap(err, "unpack event data failed") + } + // handle different kinds of event + switch abiEvent.Name { + case "BucketTypeActivated": + return s.handleBucketTypeActivatedEvent(event, blk.Timestamp()) + case "BucketTypeDeactivated": + return s.handleBucketTypeDeactivatedEvent(event) + case "Staked": + return s.handleStakedEvent(event) + case "Locked": + return s.handleLockedEvent(event) + case "Unlocked": + return s.handleUnlockedEvent(event, blk.Timestamp()) + case "Unstaked": + return s.handleUnstakedEvent(event, blk.Timestamp()) + case "Merged": + return s.handleMergedEvent(event) + case "DurationExtended": + return s.handleDurationExtendedEvent(event) + case "AmountIncreased": + return s.handleAmountIncreasedEvent(event) + case "DelegateChanged": + return s.handleDelegateChangedEvent(event) + case "Withdrawal": + return s.handleWithdrawalEvent(event) + default: + return nil + } +} + +func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, timeStamp time.Time) error { + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + bt := BucketType{ + Amount: amountParam, + Duration: s.blockHeightToDuration(durationParam.Uint64()), + ActivatedAt: &timeStamp, + } + id, ok := s.getBucketTypeIndex(amountParam, bt.Duration) + if ok { + s.bucketTypes[id] = &bt + } else { + s.bucketTypes = append(s.bucketTypes, &bt) + } + return nil +} + +func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam) error { + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + id := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + s.bucketTypes[id].ActivatedAt = nil + return nil +} + +func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + delegateParam, err := event.fieldBytes12("delegate") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + btIdx := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + bucket := BucketInfo{ + TypeIndex: btIdx, + Delegate: string(delegateParam[:]), + } + s.bucketMap[tokenIDParam.Uint64()] = &bucket + return nil +} + +func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + bt := s.bucketTypes[b.TypeIndex] + newBtIdx := s.mustGetBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + b.TypeIndex = newBtIdx + b.UnlockedAt = nil + return nil +} + +func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp time.Time) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + b.UnlockedAt = ×tamp + return nil +} + +func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp time.Time) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + b.UnstakedAt = ×tamp + return nil +} + +func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { + tokenIDsParam, err := event.fieldUint256Slice("tokenIds") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + // merge to the first bucket + btIdx := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + b := s.mustGetBucket(tokenIDsParam[0].Uint64()) + b.TypeIndex = btIdx + b.UnlockedAt = nil + for i := 1; i < len(tokenIDsParam); i++ { + s.burnBucket(tokenIDsParam[i].Uint64()) + } + return nil +} + +func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + bt := s.bucketTypes[b.TypeIndex] + newBtIdx := s.mustGetBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + b.TypeIndex = newBtIdx + return nil +} + +func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + bt := s.bucketTypes[b.TypeIndex] + newBtIdx := s.mustGetBucketTypeIndex(amountParam, bt.Duration) + b.TypeIndex = newBtIdx + return nil +} + +func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + delegateParam, err := event.fieldBytes12("newDelegate") + if err != nil { + return err + } + + b := s.mustGetBucket(tokenIDParam.Uint64()) + b.Delegate = string(delegateParam[:]) + return nil +} + +func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { + tokenIDParam, err := event.fieldUint256("tokenId") + if err != nil { + return err + } + + s.burnBucket(tokenIDParam.Uint64()) + return nil +} + +func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + if m, ok := s.bucketTypeMap[amount.Int64()]; ok { + if index, ok := m[int64(duration)]; ok { + return index, true + } + } + return 0, false +} + +func (s *liquidStakingIndexer) mustGetBucketTypeIndex(amount *big.Int, duration time.Duration) uint64 { + idx, ok := s.getBucketTypeIndex(amount, duration) + if !ok { + log.S().Panic("bucket type not found", zap.Uint64("amount", amount.Uint64()), zap.Uint64("duration", uint64(duration))) + } + return idx +} + +func (s *liquidStakingIndexer) mustGetBucket(token uint64) *BucketInfo { + b, ok := s.bucketMap[token] + if !ok { + log.S().Panic("bucket not found", zap.Uint64("tokenID", token)) + } + return b +} + +func (s *liquidStakingIndexer) burnBucket(token uint64) { + delete(s.bucketMap, token) +} + +func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { + return time.Duration(height) * s.blockInterval +} + +func (e eventParam) fieldUint256(name string) (*big.Int, error) { + field, ok := e[name].(*big.Int) + if !ok { + return nil, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + } + return field, nil +} + +func (e eventParam) fieldBytes12(name string) ([12]byte, error) { + field, ok := e[name].([12]byte) + if !ok { + return [12]byte{}, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + } + return field, nil +} + +func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { + field, ok := e[name].([]*big.Int) + if !ok { + return nil, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + } + return field, nil +} + +func (e eventParam) fieldAddress(name string) (common.Address, error) { + field, ok := e[name].(common.Address) + if !ok { + return common.Address{}, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + } + return field, nil +} diff --git a/blockindex/systemstaking_indexer.go b/blockindex/systemstaking_indexer.go deleted file mode 100644 index a3a0cd0cd1..0000000000 --- a/blockindex/systemstaking_indexer.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2023 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package blockindex - -import ( - "context" - "math/big" - - "github.com/iotexproject/iotex-core/action/protocol/staking" - "github.com/iotexproject/iotex-core/blockchain/block" - "github.com/iotexproject/iotex-core/blockchain/blockdao" -) - -type ( - // SystemStakingIndexer is the interface of system staking indexer - SystemStakingIndexer interface { - blockdao.BlockIndexer - - GetCandidateVotes(candidate string) (*big.Int, error) - GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) - } - - systemStakingIndexer struct{} -) - -// NewSystemStakingIndexer creates a new system staking indexer -func NewSystemStakingIndexer() SystemStakingIndexer { - return &systemStakingIndexer{} -} - -func (s *systemStakingIndexer) Start(ctx context.Context) error { - return nil -} - -func (s *systemStakingIndexer) Stop(ctx context.Context) error { - return nil -} - -func (s *systemStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { - return nil -} - -func (s *systemStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { - return nil -} - -func (s *systemStakingIndexer) Height() (uint64, error) { - return 0, nil -} - -func (s *systemStakingIndexer) GetCandidateVotes(candidate string) (*big.Int, error) { - return nil, nil -} - -func (s *systemStakingIndexer) GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) { - return nil, nil -} diff --git a/chainservice/builder.go b/chainservice/builder.go index abe36233c6..9bf645c9ee 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -241,7 +241,7 @@ func (builder *Builder) buildActionPool() error { } func (builder *Builder) buildSystemStakingIndexer() error { - builder.cs.systemStakingIndexer = blockindex.NewSystemStakingIndexer() + builder.cs.liquidStakingIndexer = blockindex.NewLiquidStakingIndexer() return nil } @@ -251,7 +251,7 @@ func (builder *Builder) buildBlockDAO(forTest bool) error { } var indexers []blockdao.BlockIndexer - indexers = append(indexers, builder.cs.factory, builder.cs.systemStakingIndexer) + indexers = append(indexers, builder.cs.factory, builder.cs.liquidStakingIndexer) if !builder.cfg.Chain.EnableAsyncIndexWrite && builder.cs.indexer != nil { indexers = append(indexers, builder.cs.indexer) } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index badee49207..0e27f6e004 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -86,7 +86,7 @@ type ChainService struct { candBucketsIndexer *staking.CandidatesBucketsIndexer registry *protocol.Registry nodeInfoManager *nodeinfo.InfoManager - systemStakingIndexer blockindex.SystemStakingIndexer + liquidStakingIndexer blockindex.LiquidStakingIndexer } // Start starts the server diff --git a/e2etest/contract_test.go b/e2etest/contract_test.go new file mode 100644 index 0000000000..8e56b49f53 --- /dev/null +++ b/e2etest/contract_test.go @@ -0,0 +1,163 @@ +package e2etest + +import ( + "context" + "encoding/hex" + "math/big" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-core/action" + "github.com/iotexproject/iotex-core/action/protocol" + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/config" + "github.com/iotexproject/iotex-core/pkg/unit" + "github.com/iotexproject/iotex-core/server/itx" + "github.com/iotexproject/iotex-core/state" + "github.com/iotexproject/iotex-core/test/identityset" + "github.com/iotexproject/iotex-core/testutil" + "github.com/stretchr/testify/require" +) + +func TestContract(t *testing.T) { + require := require.New(t) + + testReadContract := func(cfg config.Config, t *testing.T) { + ctx := context.Background() + + // Create a new blockchain + svr, err := itx.NewServer(cfg) + require.NoError(err) + require.NoError(svr.Start(ctx)) + defer func() { + require.NoError(svr.Stop(ctx)) + }() + + chainID := cfg.Chain.ID + bc := svr.ChainService(chainID).Blockchain() + sf := svr.ChainService(chainID).StateFactory() + ap := svr.ChainService(chainID).ActionPool() + dao := svr.ChainService(chainID).BlockDAO() + registry := svr.ChainService(chainID).Registry() + require.NotNil(bc) + require.NotNil(registry) + admin := identityset.PrivateKey(26) + state0 := hash.BytesToHash160(identityset.Address(26).Bytes()) + s := &state.Account{} + _, err = sf.State(s, protocol.LegacyKeyOption(state0)) + require.NoError(err) + require.Equal(unit.ConvertIotxToRau(100000000), s.Balance) + + // deploy staking contract + data, _ := hex.DecodeString("608060405234801561001057600080fd5b50610187806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b610055600480360381019061005091906100fa565b610075565b005b61005f6100b6565b60405161006c9190610136565b60405180910390f35b806000819055507fdf7a95aebff315db1b7716215d602ab537373cdb769232aae6055c06e798425b816040516100ab9190610136565b60405180910390a150565b60008054905090565b600080fd5b6000819050919050565b6100d7816100c4565b81146100e257600080fd5b50565b6000813590506100f4816100ce565b92915050565b6000602082840312156101105761010f6100bf565b5b600061011e848285016100e5565b91505092915050565b610130816100c4565b82525050565b600060208201905061014b6000830184610127565b9291505056fea2646970667358221220f5056e078d0c1d02dd0cbf9d99c912c45a3d2078427fcf18f7f7eb1b15b263fb64736f6c63430008110033") + fixedTime := time.Unix(cfg.Genesis.Timestamp, 0) + ex, err := action.SignedExecution(action.EmptyAddress, admin, 1, big.NewInt(0), 10000000, big.NewInt(testutil.TestGasPriceInt64), data) + require.NoError(err) + + deployHash, err := ex.Hash() + require.NoError(err) + require.NoError(ap.Add(context.Background(), ex)) + blk, err := bc.MintNewBlock(fixedTime) + require.NoError(err) + require.NoError(bc.CommitBlock(blk)) + r, err := dao.GetReceiptByActionHash(deployHash, 1) + require.NoError(err) + require.Equal(r.ContractAddress, "io123vqxxup8n3ld8jygvx729r6295pv9krjn2tjh") + + // set value + _abi := `[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"Set","type":"event"},{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}]` + contractABI, err := abi.JSON(strings.NewReader(_abi)) + require.NoError(err) + fixedAmount := unit.ConvertIotxToRau(200) + sk := identityset.PrivateKey(26) + nonce := uint64(0) + data, err = contractABI.Pack("set", big.NewInt(10)) + require.NoError(err) + require.True(len(data) > 0) + ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) + require.NoError(err) + require.NoError(ap.Add(context.Background(), ex)) + // data, err = contractABI.Pack("get") + // require.NoError(err) + // require.True(len(data) > 0) + // ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) + // require.NoError(err) + // require.NoError(ap.Add(context.Background(), ex)) + blk, err = bc.MintNewBlock(fixedTime) + require.NoError(err) + require.NoError(bc.CommitBlock(blk)) + } + + cfg := config.Default + testTriePath, err := testutil.PathOfTempFile("trie") + require.NoError(err) + testDBPath, err := testutil.PathOfTempFile("db") + require.NoError(err) + testIndexPath, err := testutil.PathOfTempFile("index") + require.NoError(err) + testBloomfilterIndexPath, err := testutil.PathOfTempFile("bloomfilterindex") + require.NoError(err) + testCandidateIndexPath, err := testutil.PathOfTempFile("candidateindex") + require.NoError(err) + testSystemLogPath, err := testutil.PathOfTempFile("systemlog") + require.NoError(err) + testConsensusPath, err := testutil.PathOfTempFile("consensus") + require.NoError(err) + defer func() { + testutil.CleanupPath(testTriePath) + testutil.CleanupPath(testDBPath) + testutil.CleanupPath(testIndexPath) + testutil.CleanupPath(testBloomfilterIndexPath) + testutil.CleanupPath(testCandidateIndexPath) + testutil.CleanupPath(testSystemLogPath) + testutil.CleanupPath(testConsensusPath) + // clear the gateway + delete(cfg.Plugins, config.GatewayPlugin) + }() + + cfg.ActPool.MinGasPriceStr = "0" + cfg.Chain.TrieDBPatchFile = "" + cfg.Chain.TrieDBPath = testTriePath + cfg.Chain.ChainDBPath = testDBPath + cfg.Chain.IndexDBPath = testIndexPath + cfg.Chain.BloomfilterIndexDBPath = testBloomfilterIndexPath + cfg.Chain.CandidateIndexDBPath = testCandidateIndexPath + cfg.System.SystemLogDBPath = testSystemLogPath + cfg.Consensus.RollDPoS.ConsensusDBPath = testConsensusPath + cfg.Chain.ProducerPrivKey = "a000000000000000000000000000000000000000000000000000000000000000" + cfg.Consensus.Scheme = config.RollDPoSScheme + // cfg.Genesis.Blockchain = genesis.Blockchain{ + // Timestamp: config.Default.Genesis.Timestamp, + // BlockGasLimit: config.Default.Genesis.BlockGasLimit, + // ActionGasLimit: config.Default.Genesis.ActionGasLimit, + // BlockInterval: config.Default.Genesis.BlockInterval, + // NumSubEpochs: uint64(config.Default.Genesis.NumSubEpochs), + // DardanellesNumSubEpochs: uint64(config.Default.Genesis.DardanellesNumSubEpochs), + // NumDelegates: uint64(config.Default.Genesis.NumDelegates), + // NumCandidateDelegates: uint64(config.Default.Genesis.NumCandidateDelegates), + // TimeBasedRotation: config.Default.Genesis.TimeBasedRotation, + // } + cfg.Genesis.NumDelegates = 1 + cfg.Genesis.NumSubEpochs = 10 + cfg.Genesis.Delegates = []genesis.Delegate{ + { + OperatorAddrStr: identityset.Address(0).String(), + RewardAddrStr: identityset.Address(0).String(), + VotesStr: "10", + }, + } + cfg.Genesis.PollMode = "lifeLong" + cfg.Genesis.EnableGravityChainVoting = false + cfg.Plugins[config.GatewayPlugin] = true + cfg.Chain.EnableAsyncIndexWrite = false + cfg.Genesis.AleutianBlockHeight = 2 + cfg.Genesis.BeringBlockHeight = 0 + cfg.Genesis.HawaiiBlockHeight = 0 + + t.Run("test read staking contract", func(t *testing.T) { + testReadContract(cfg, t) + }) +} From 17fc4779093a020b526ac13ab5fa27831d7d92d9 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 21 Apr 2023 15:21:36 +0800 Subject: [PATCH 03/51] use generic func --- blockindex/liquidstaking_indexer.go | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 2c6cf24412..3d835f3c41 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -18,6 +18,7 @@ import ( "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" "go.uber.org/zap" ) @@ -134,6 +135,9 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { for _, receipt := range blk.Receipts { + if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { + continue + } for _, log := range receipt.Logs() { if log.Address != LiquidStakingContractAddress { continue @@ -425,34 +429,26 @@ func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duratio return time.Duration(height) * s.blockInterval } -func (e eventParam) fieldUint256(name string) (*big.Int, error) { - field, ok := e[name].(*big.Int) +func eventField[T any](e eventParam, name string) (T, error) { + field, ok := e[name].(T) if !ok { - return nil, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + return field, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) } return field, nil } +func (e eventParam) fieldUint256(name string) (*big.Int, error) { + return eventField[*big.Int](e, name) +} + func (e eventParam) fieldBytes12(name string) ([12]byte, error) { - field, ok := e[name].([12]byte) - if !ok { - return [12]byte{}, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) - } - return field, nil + return eventField[[12]byte](e, name) } func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { - field, ok := e[name].([]*big.Int) - if !ok { - return nil, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) - } - return field, nil + return eventField[[]*big.Int](e, name) } func (e eventParam) fieldAddress(name string) (common.Address, error) { - field, ok := e[name].(common.Address) - if !ok { - return common.Address{}, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) - } - return field, nil + return eventField[common.Address](e, name) } From ed2fc4ecb37060a95432a848d4767e0b3bb1afa4 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 21 Apr 2023 15:45:23 +0800 Subject: [PATCH 04/51] refactor --- blockindex/liquidstaking_indexer.go | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 3d835f3c41..c3d725a02d 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -17,6 +17,7 @@ import ( "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" + "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" @@ -81,6 +82,8 @@ type ( } liquidStakingIndexer struct { + kvStore db.KVStore + bucketMap map[uint64]*BucketInfo // map[token]bucketInfo bucketTypes []*BucketType bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index @@ -180,30 +183,31 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block // handle different kinds of event switch abiEvent.Name { case "BucketTypeActivated": - return s.handleBucketTypeActivatedEvent(event, blk.Timestamp()) + err = s.handleBucketTypeActivatedEvent(event, blk.Timestamp()) case "BucketTypeDeactivated": - return s.handleBucketTypeDeactivatedEvent(event) + err = s.handleBucketTypeDeactivatedEvent(event) case "Staked": - return s.handleStakedEvent(event) + err = s.handleStakedEvent(event) case "Locked": - return s.handleLockedEvent(event) + err = s.handleLockedEvent(event) case "Unlocked": - return s.handleUnlockedEvent(event, blk.Timestamp()) + err = s.handleUnlockedEvent(event, blk.Timestamp()) case "Unstaked": - return s.handleUnstakedEvent(event, blk.Timestamp()) + err = s.handleUnstakedEvent(event, blk.Timestamp()) case "Merged": - return s.handleMergedEvent(event) + err = s.handleMergedEvent(event) case "DurationExtended": - return s.handleDurationExtendedEvent(event) + err = s.handleDurationExtendedEvent(event) case "AmountIncreased": - return s.handleAmountIncreasedEvent(event) + err = s.handleAmountIncreasedEvent(event) case "DelegateChanged": - return s.handleDelegateChangedEvent(event) + err = s.handleDelegateChangedEvent(event) case "Withdrawal": - return s.handleWithdrawalEvent(event) + err = s.handleWithdrawalEvent(event) default: - return nil + err = nil } + return err } func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, timeStamp time.Time) error { From 0a910a8ef3f1d20da6fe06462e344cde59d4dd88 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 21 Apr 2023 21:53:16 +0800 Subject: [PATCH 05/51] refactor --- blockindex/liquidstaking_indexer.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index c3d725a02d..b146efe23f 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -112,7 +112,7 @@ type ( var ( _liquidStakingInterface abi.ABI - errUnpackEvent = errors.New("failed to unpack event") + errInvlidEventParam = errors.New("invalid event param") ) func init() { @@ -175,11 +175,13 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block if err != nil { return errors.Wrapf(err, "get event abi from topic %v failed", log.Topics[0]) } + // unpack event data - event := make(map[string]any) + event := make(eventParam) if err = abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { return errors.Wrap(err, "unpack event data failed") } + // handle different kinds of event switch abiEvent.Name { case "BucketTypeActivated": @@ -436,7 +438,7 @@ func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duratio func eventField[T any](e eventParam, name string) (T, error) { field, ok := e[name].(T) if !ok { - return field, errors.Wrapf(errUnpackEvent, "invalid %s %v", name, e[name]) + return field, errors.Wrapf(errInvlidEventParam, "field %s got %#v, expect %T", name, e[name], field) } return field, nil } From 120cd8d801e6524a0d485a8e18b6044b546b158d Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 21 Apr 2023 23:42:42 +0800 Subject: [PATCH 06/51] add data to dirty write --- blockindex/liquidstaking_indexer.go | 293 ++++++++++++++++++++++------ 1 file changed, 233 insertions(+), 60 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index b146efe23f..3afba5f763 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -7,6 +7,8 @@ package blockindex import ( "context" + "encoding/binary" + "encoding/json" "math/big" "strings" "time" @@ -18,6 +20,7 @@ import ( "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/log" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" @@ -70,6 +73,11 @@ const ( "type": "function" } ]` + + _liquidStakingBucketInfoNS = "lsdBucketInfo" + _liquidStakingBucketTypeNS = "lsdBucketType" + _liquidStakingBucketTypeMapNS = "lsdBucketTypeMap" + _liquidStakingBucketTypeCountNS = "lsdBucketTypeCount" ) type ( @@ -82,15 +90,22 @@ type ( } liquidStakingIndexer struct { - kvStore db.KVStore - - bucketMap map[uint64]*BucketInfo // map[token]bucketInfo - bucketTypes []*BucketType - bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + data *liquidStakingData blockInterval time.Duration } + liquidStakingData struct { + // dirty data in memory + batch batch.CachedBatch + // clean data in db + kvStore db.KVStore + // clean data cache in memory + // bucketMap map[uint64]*BucketInfo // map[token]bucketInfo + // bucketTypes []*BucketType + // bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + } + // BucketInfo is the bucket information BucketInfo struct { TypeIndex uint64 @@ -137,6 +152,7 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { } func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { + s.data.newBatch() for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue @@ -150,7 +166,7 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } } } - return nil + return s.data.commit() } func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { @@ -227,12 +243,17 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, Duration: s.blockHeightToDuration(durationParam.Uint64()), ActivatedAt: &timeStamp, } - id, ok := s.getBucketTypeIndex(amountParam, bt.Duration) - if ok { - s.bucketTypes[id] = &bt - } else { - s.bucketTypes = append(s.bucketTypes, &bt) + id, err := s.data.getBucketTypeIndex(amountParam, bt.Duration) + if err != nil { + if !errors.Is(err, batch.ErrNotExist) { + return err + } + id, err = s.data.getBucketTypeCount() + if err != nil { + return err + } } + s.data.putBucketType(id, &bt) return nil } @@ -246,8 +267,16 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return err } - id := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) - s.bucketTypes[id].ActivatedAt = nil + id, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if err != nil { + return err + } + bt, err := s.data.getBucketType(id) + if err != nil { + return err + } + bt.ActivatedAt = nil + s.data.putBucketType(id, bt) return nil } @@ -269,12 +298,15 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { return err } - btIdx := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if err != nil { + return err + } bucket := BucketInfo{ TypeIndex: btIdx, Delegate: string(delegateParam[:]), } - s.bucketMap[tokenIDParam.Uint64()] = &bucket + s.data.putBucketInfo(tokenIDParam.Uint64(), &bucket) return nil } @@ -288,11 +320,21 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) - bt := s.bucketTypes[b.TypeIndex] - newBtIdx := s.mustGetBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } + bt, err := s.data.getBucketType(b.TypeIndex) + if err != nil { + return err + } + newBtIdx, err := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + if err != nil { + return err + } b.TypeIndex = newBtIdx b.UnlockedAt = nil + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -302,8 +344,12 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } b.UnlockedAt = ×tamp + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -313,8 +359,12 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp t return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } b.UnstakedAt = ×tamp + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -333,13 +383,20 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } // merge to the first bucket - btIdx := s.mustGetBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) - b := s.mustGetBucket(tokenIDsParam[0].Uint64()) + btIdx, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if err != nil { + return err + } + b, err := s.data.getBucketInfo(tokenIDsParam[0].Uint64()) + if err != nil { + return err + } b.TypeIndex = btIdx b.UnlockedAt = nil for i := 1; i < len(tokenIDsParam); i++ { - s.burnBucket(tokenIDsParam[i].Uint64()) + s.data.burnBucket(tokenIDsParam[i].Uint64()) } + s.data.putBucketInfo(tokenIDsParam[0].Uint64(), b) return nil } @@ -353,10 +410,20 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) - bt := s.bucketTypes[b.TypeIndex] - newBtIdx := s.mustGetBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } + bt, err := s.data.getBucketType(b.TypeIndex) + if err != nil { + return err + } + newBtIdx, err := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + if err != nil { + return err + } b.TypeIndex = newBtIdx + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -370,10 +437,20 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) - bt := s.bucketTypes[b.TypeIndex] - newBtIdx := s.mustGetBucketTypeIndex(amountParam, bt.Duration) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } + bt, err := s.data.getBucketType(b.TypeIndex) + if err != nil { + return err + } + newBtIdx, err := s.data.getBucketTypeIndex(amountParam, bt.Duration) + if err != nil { + return err + } b.TypeIndex = newBtIdx + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -387,8 +464,12 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro return err } - b := s.mustGetBucket(tokenIDParam.Uint64()) + b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) + if err != nil { + return err + } b.Delegate = string(delegateParam[:]) + s.data.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -398,39 +479,10 @@ func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { return err } - s.burnBucket(tokenIDParam.Uint64()) + s.data.burnBucket(tokenIDParam.Uint64()) return nil } -func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - if m, ok := s.bucketTypeMap[amount.Int64()]; ok { - if index, ok := m[int64(duration)]; ok { - return index, true - } - } - return 0, false -} - -func (s *liquidStakingIndexer) mustGetBucketTypeIndex(amount *big.Int, duration time.Duration) uint64 { - idx, ok := s.getBucketTypeIndex(amount, duration) - if !ok { - log.S().Panic("bucket type not found", zap.Uint64("amount", amount.Uint64()), zap.Uint64("duration", uint64(duration))) - } - return idx -} - -func (s *liquidStakingIndexer) mustGetBucket(token uint64) *BucketInfo { - b, ok := s.bucketMap[token] - if !ok { - log.S().Panic("bucket not found", zap.Uint64("tokenID", token)) - } - return b -} - -func (s *liquidStakingIndexer) burnBucket(token uint64) { - delete(s.bucketMap, token) -} - func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { return time.Duration(height) * s.blockInterval } @@ -458,3 +510,124 @@ func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { func (e eventParam) fieldAddress(name string) (common.Address, error) { return eventField[common.Address](e, name) } + +func newLiquidStakingData(kvStore db.KVStore) *liquidStakingData { + return &liquidStakingData{ + kvStore: kvStore, + batch: batch.NewCachedBatch(), + } +} + +// newBatch +func (s *liquidStakingData) newBatch() { + s.batch.Clear() +} + +// getBucketTypeIndex +func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, error) { + d := make([]byte, 8) + binary.LittleEndian.PutUint64(d, uint64(duration)) + amountKey := []byte("amount") + durationKey := []byte("duration") + key := append(amountKey, amount.Bytes()...) + key = append(key, durationKey...) + key = append(key, d...) + + v, err := s.get(_liquidStakingBucketTypeMapNS, key) + if err != nil { + return 0, err + } + return binary.LittleEndian.Uint64(v), nil +} + +// get bucket type count +func (s *liquidStakingData) getBucketTypeCount() (uint64, error) { + v, err := s.get(_liquidStakingBucketTypeCountNS, []byte("count")) + if err != nil { + return 0, err + } + return binary.LittleEndian.Uint64(v), nil +} + +// get bucket type +func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, error) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, id) + v, err := s.get(_liquidStakingBucketTypeNS, key) + if err != nil { + return nil, err + } + var bt BucketType + if err := json.Unmarshal(v, &bt); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal bucket type") + } + return &bt, nil +} + +func (s *liquidStakingData) get(ns string, key []byte) ([]byte, error) { + v, err := s.batch.Get(ns, key) + if err != nil { + if !errors.Is(err, batch.ErrNotExist) { + return nil, err + } + v, err = s.kvStore.Get(ns, key) + } + return v, err +} + +// putBucketType +func (s *liquidStakingData) putBucketType(id uint64, bt *BucketType) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, id) + s.batch.Put(_liquidStakingBucketTypeNS, key, bt.serialize(), "failed to put bucket type") +} + +// putBucketInfo +func (s *liquidStakingData) putBucketInfo(id uint64, bi *BucketInfo) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, id) + s.batch.Put(_liquidStakingBucketInfoNS, key, bi.serialize(), "failed to put bucket info") +} + +// getBucketInfo +func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, error) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, id) + v, err := s.get(_liquidStakingBucketInfoNS, key) + if err != nil { + return nil, err + } + var bi BucketInfo + if err := json.Unmarshal(v, &bi); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal bucket info") + } + return &bi, nil +} + +// burnBucket +func (s *liquidStakingData) burnBucket(id uint64) { + key := make([]byte, 8) + binary.LittleEndian.PutUint64(key, id) + s.batch.Delete(_liquidStakingBucketInfoNS, key, "failed to delete bucket info") +} + +// commit() +func (s *liquidStakingData) commit() error { + return s.kvStore.WriteBatch(s.batch) +} + +func (bt *BucketType) serialize() []byte { + b, err := json.Marshal(bt) + if err != nil { + log.S().Panic("marshal bucket type", zap.Error(err)) + } + return b +} + +func (bi *BucketInfo) serialize() []byte { + b, err := json.Marshal(bi) + if err != nil { + log.S().Panic("marshal bucket info", zap.Error(err)) + } + return b +} From deaf0ae6d56083b64fbe7c7b8154394cb9da6c2f Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 24 Apr 2023 21:41:31 +0800 Subject: [PATCH 07/51] add index cache --- blockindex/liquidstaking_cache.go | 57 ++++++ blockindex/liquidstaking_indexer.go | 297 +++++++++++++++------------- 2 files changed, 213 insertions(+), 141 deletions(-) create mode 100644 blockindex/liquidstaking_cache.go diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go new file mode 100644 index 0000000000..e525b2b1dc --- /dev/null +++ b/blockindex/liquidstaking_cache.go @@ -0,0 +1,57 @@ +package blockindex + +import ( + "math/big" + "time" + + "github.com/iotexproject/iotex-core/db/batch" +) + +type ( + liquidStakingCache struct { + bucketMap map[uint64]*BucketInfo // map[token]bucketInfo + bucketTypes map[uint64]*BucketType + bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + } +) + +func newLiquidStakingCache() *liquidStakingCache { + return &liquidStakingCache{ + bucketMap: make(map[uint64]*BucketInfo), + bucketTypes: make(map[uint64]*BucketType), + bucketTypeMap: make(map[int64]map[int64]uint64), + } +} + +func (s *liquidStakingCache) writeBatch(batch batch.KVStoreBatch) error { + // TODO (iip-13): index write batch + return nil +} + +func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { + s.bucketTypes[id] = bt + s.bucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id +} + +func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { + s.bucketMap[id] = bi +} + +func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + m, ok := s.bucketTypeMap[amount.Int64()] + if !ok { + return 0, false + } + id, ok := m[int64(duration)] + return id, ok +} + +func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.bucketTypes[id] + return bt, ok +} + +func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.bucketMap[id] + return bi, ok +} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 3afba5f763..266ff4b027 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -74,10 +74,14 @@ const ( } ]` - _liquidStakingBucketInfoNS = "lsdBucketInfo" - _liquidStakingBucketTypeNS = "lsdBucketType" - _liquidStakingBucketTypeMapNS = "lsdBucketTypeMap" - _liquidStakingBucketTypeCountNS = "lsdBucketTypeCount" + // bucket related namespace in db + _liquidStakingBucketInfoNS = "lsbInfo" + _liquidStakingBucketTypeNS = "lsbType" + _liquidStakingBucketTypeMapNS = "lsbTypeMap" + _liquidStakingBucketTypeCountNS = "lsbTypeCount" + + // bucket cache size + _liquidStakingBucketCacheSize = 10000 ) type ( @@ -96,14 +100,10 @@ type ( } liquidStakingData struct { - // dirty data in memory - batch batch.CachedBatch - // clean data in db - kvStore db.KVStore - // clean data cache in memory - // bucketMap map[uint64]*BucketInfo // map[token]bucketInfo - // bucketTypes []*BucketType - // bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + dirty batch.CachedBatch // im-memory dirty data + dirtyCache *liquidStakingCache + clean db.KVStore // clean data in db + cleanCache *liquidStakingCache // in-memory index for clean data } // BucketInfo is the bucket information @@ -121,13 +121,17 @@ type ( ActivatedAt *time.Time } + // eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type + // TODO: this is general enough to be moved to a common package eventParam map[string]any ) var ( _liquidStakingInterface abi.ABI - errInvlidEventParam = errors.New("invalid event param") + errInvlidEventParam = errors.New("invalid event param") + errBucketTypeNotExist = errors.New("bucket type does not exist") + errBucketInfoNotExist = errors.New("bucket info does not exist") ) func init() { @@ -152,7 +156,6 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { } func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { - s.data.newBatch() for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue @@ -243,15 +246,9 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, Duration: s.blockHeightToDuration(durationParam.Uint64()), ActivatedAt: &timeStamp, } - id, err := s.data.getBucketTypeIndex(amountParam, bt.Duration) - if err != nil { - if !errors.Is(err, batch.ErrNotExist) { - return err - } - id, err = s.data.getBucketTypeCount() - if err != nil { - return err - } + id, ok := s.data.getBucketTypeIndex(amountParam, bt.Duration) + if !ok { + id = s.data.getBucketTypeCount() } s.data.putBucketType(id, &bt) return nil @@ -267,13 +264,13 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return err } - id, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) - if err != nil { - return err + id, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - bt, err := s.data.getBucketType(id) - if err != nil { - return err + bt, ok := s.data.getBucketType(id) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } bt.ActivatedAt = nil s.data.putBucketType(id, bt) @@ -298,9 +295,9 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { return err } - btIdx, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) - if err != nil { - return err + btIdx, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } bucket := BucketInfo{ TypeIndex: btIdx, @@ -320,17 +317,17 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, err := s.data.getBucketType(b.TypeIndex) - if err != nil { - return err + bt, ok := s.data.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, err := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) - if err != nil { - return err + newBtIdx, ok := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } b.TypeIndex = newBtIdx b.UnlockedAt = nil @@ -344,9 +341,9 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnlockedAt = ×tamp s.data.putBucketInfo(tokenIDParam.Uint64(), b) @@ -359,9 +356,9 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp t return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnstakedAt = ×tamp s.data.putBucketInfo(tokenIDParam.Uint64(), b) @@ -383,13 +380,13 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } // merge to the first bucket - btIdx, err := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) - if err != nil { - return err + btIdx, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - b, err := s.data.getBucketInfo(tokenIDsParam[0].Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDsParam[0].Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx b.UnlockedAt = nil @@ -410,17 +407,17 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, err := s.data.getBucketType(b.TypeIndex) - if err != nil { - return err + bt, ok := s.data.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, err := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) - if err != nil { - return err + newBtIdx, ok := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } b.TypeIndex = newBtIdx s.data.putBucketInfo(tokenIDParam.Uint64(), b) @@ -437,17 +434,17 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, err := s.data.getBucketType(b.TypeIndex) - if err != nil { - return err + bt, ok := s.data.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, err := s.data.getBucketTypeIndex(amountParam, bt.Duration) - if err != nil { - return err + newBtIdx, ok := s.data.getBucketTypeIndex(amountParam, bt.Duration) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) } b.TypeIndex = newBtIdx s.data.putBucketInfo(tokenIDParam.Uint64(), b) @@ -464,9 +461,9 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro return err } - b, err := s.data.getBucketInfo(tokenIDParam.Uint64()) - if err != nil { - return err + b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.Delegate = string(delegateParam[:]) s.data.putBucketInfo(tokenIDParam.Uint64(), b) @@ -511,109 +508,127 @@ func (e eventParam) fieldAddress(name string) (common.Address, error) { return eventField[common.Address](e, name) } -func newLiquidStakingData(kvStore db.KVStore) *liquidStakingData { - return &liquidStakingData{ - kvStore: kvStore, - batch: batch.NewCachedBatch(), +func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { + data := liquidStakingData{ + dirty: batch.NewCachedBatch(), + clean: kvStore, + cleanCache: newLiquidStakingCache(), + dirtyCache: newLiquidStakingCache(), } + return &data, nil } -// newBatch -func (s *liquidStakingData) newBatch() { - s.batch.Clear() -} - -// getBucketTypeIndex -func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, error) { - d := make([]byte, 8) - binary.LittleEndian.PutUint64(d, uint64(duration)) - amountKey := []byte("amount") - durationKey := []byte("duration") - key := append(amountKey, amount.Bytes()...) - key = append(key, durationKey...) - key = append(key, d...) - - v, err := s.get(_liquidStakingBucketTypeMapNS, key) +func (s *liquidStakingData) loadCache() error { + ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { - return 0, err + if !errors.Is(err, db.ErrNotExist) { + return err + } + } + for i := range vs { + var b BucketInfo + if err := json.Unmarshal(vs[i], &b); err != nil { + return err + } + s.cleanCache.putBucketInfo(binary.LittleEndian.Uint64(ks[i]), &b) } - return binary.LittleEndian.Uint64(v), nil -} -// get bucket type count -func (s *liquidStakingData) getBucketTypeCount() (uint64, error) { - v, err := s.get(_liquidStakingBucketTypeCountNS, []byte("count")) + ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { - return 0, err + if !errors.Is(err, db.ErrNotExist) { + return err + } } - return binary.LittleEndian.Uint64(v), nil + for i := range vs { + var b BucketType + if err := json.Unmarshal(vs[i], &b); err != nil { + return err + } + s.cleanCache.putBucketType(binary.LittleEndian.Uint64(ks[i]), &b) + } + return nil } -// get bucket type -func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, error) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, id) - v, err := s.get(_liquidStakingBucketTypeNS, key) - if err != nil { - return nil, err - } - var bt BucketType - if err := json.Unmarshal(v, &bt); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal bucket type") +func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) + if ok { + return id, true } - return &bt, nil + id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) + return id, ok } -func (s *liquidStakingData) get(ns string, key []byte) ([]byte, error) { - v, err := s.batch.Get(ns, key) - if err != nil { - if !errors.Is(err, batch.ErrNotExist) { - return nil, err +func (s *liquidStakingData) getBucketTypeCount() uint64 { + base := len(s.cleanCache.bucketTypes) + add := 0 + for k, dbt := range s.dirtyCache.bucketTypes { + _, ok := s.cleanCache.bucketTypes[k] + if dbt != nil && !ok { + add++ + } else if dbt == nil && ok { + add-- } - v, err = s.kvStore.Get(ns, key) } - return v, err + return uint64(base + add) +} + +func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.dirtyCache.getBucketType(id) + if ok { + return bt, true + } + bt, ok = s.cleanCache.getBucketType(id) + return bt, ok } -// putBucketType func (s *liquidStakingData) putBucketType(id uint64, bt *BucketType) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, id) - s.batch.Put(_liquidStakingBucketTypeNS, key, bt.serialize(), "failed to put bucket type") + s.dirty.Put(_liquidStakingBucketTypeNS, key, bt.serialize(), "failed to put bucket type") + s.dirtyCache.putBucketType(id, bt) } -// putBucketInfo func (s *liquidStakingData) putBucketInfo(id uint64, bi *BucketInfo) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, id) - s.batch.Put(_liquidStakingBucketInfoNS, key, bi.serialize(), "failed to put bucket info") + s.dirty.Put(_liquidStakingBucketInfoNS, key, bi.serialize(), "failed to put bucket info") + s.dirtyCache.putBucketInfo(id, bi) } -// getBucketInfo -func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, error) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, id) - v, err := s.get(_liquidStakingBucketInfoNS, key) - if err != nil { - return nil, err - } - var bi BucketInfo - if err := json.Unmarshal(v, &bi); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal bucket info") +func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.dirtyCache.getBucketInfo(id) + if ok { + return bi, bi != nil } - return &bi, nil + bi, ok = s.cleanCache.getBucketInfo(id) + return bi, ok } -// burnBucket func (s *liquidStakingData) burnBucket(id uint64) { key := make([]byte, 8) binary.LittleEndian.PutUint64(key, id) - s.batch.Delete(_liquidStakingBucketInfoNS, key, "failed to delete bucket info") + s.dirty.Delete(_liquidStakingBucketInfoNS, key, "failed to delete bucket info") + s.dirtyCache.putBucketInfo(id, nil) } -// commit() +// GetBuckets(height uint64, offset, limit uint32) +// BucketsByVoter(voterAddr string, offset, limit uint32) +// BucketsByCandidate(candidateAddr string, offset, limit uint32) +// BucketByIndices(indecis []uint64) +// BucketCount() +// TotalStakingAmount() + func (s *liquidStakingData) commit() error { - return s.kvStore.WriteBatch(s.batch) + if err := s.cleanCache.writeBatch(s.dirty); err != nil { + return err + } + if err := s.clean.WriteBatch(s.dirty); err != nil { + return err + } + s.dirty.Lock() + s.dirty.ClearAndUnlock() + s.dirtyCache = newLiquidStakingCache() + return nil } func (bt *BucketType) serialize() []byte { From b32acfc9a3e6951c502495432611bd3ba5df67ab Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 24 Apr 2023 22:36:29 +0800 Subject: [PATCH 08/51] add proto --- blockindex/indexpb/liquidstaking_bucket.pb.go | 279 ++++++++++++++++++ blockindex/indexpb/liquidstaking_bucket.proto | 24 ++ blockindex/liquidstaking_cache.go | 57 ---- blockindex/liquidstaking_data.go | 183 ++++++++++++ blockindex/liquidstaking_indexer.go | 174 ++++------- 5 files changed, 536 insertions(+), 181 deletions(-) create mode 100644 blockindex/indexpb/liquidstaking_bucket.pb.go create mode 100644 blockindex/indexpb/liquidstaking_bucket.proto delete mode 100644 blockindex/liquidstaking_cache.go create mode 100644 blockindex/liquidstaking_data.go diff --git a/blockindex/indexpb/liquidstaking_bucket.pb.go b/blockindex/indexpb/liquidstaking_bucket.pb.go new file mode 100644 index 0000000000..690d64f079 --- /dev/null +++ b/blockindex/indexpb/liquidstaking_bucket.pb.go @@ -0,0 +1,279 @@ +// Copyright (c) 2019 IoTeX +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +// To compile the proto, run: +// protoc --go_out=plugins=grpc:. *.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.12 +// source: blockindex/indexpb/liquidstaking_bucket.proto + +package indexpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type BucketType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + Duration uint64 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"` + ActivatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=activatedAt,proto3" json:"activatedAt,omitempty"` +} + +func (x *BucketType) Reset() { + *x = BucketType{} + if protoimpl.UnsafeEnabled { + mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BucketType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BucketType) ProtoMessage() {} + +func (x *BucketType) ProtoReflect() protoreflect.Message { + mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BucketType.ProtoReflect.Descriptor instead. +func (*BucketType) Descriptor() ([]byte, []int) { + return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP(), []int{0} +} + +func (x *BucketType) GetAmount() string { + if x != nil { + return x.Amount + } + return "" +} + +func (x *BucketType) GetDuration() uint64 { + if x != nil { + return x.Duration + } + return 0 +} + +func (x *BucketType) GetActivatedAt() *timestamppb.Timestamp { + if x != nil { + return x.ActivatedAt + } + return nil +} + +type BucketInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TypeIndex uint64 `protobuf:"varint,1,opt,name=typeIndex,proto3" json:"typeIndex,omitempty"` + UnlockedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` + UnstakedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` + Delegate string `protobuf:"bytes,4,opt,name=delegate,proto3" json:"delegate,omitempty"` +} + +func (x *BucketInfo) Reset() { + *x = BucketInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BucketInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BucketInfo) ProtoMessage() {} + +func (x *BucketInfo) ProtoReflect() protoreflect.Message { + mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BucketInfo.ProtoReflect.Descriptor instead. +func (*BucketInfo) Descriptor() ([]byte, []int) { + return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP(), []int{1} +} + +func (x *BucketInfo) GetTypeIndex() uint64 { + if x != nil { + return x.TypeIndex + } + return 0 +} + +func (x *BucketInfo) GetUnlockedAt() *timestamppb.Timestamp { + if x != nil { + return x.UnlockedAt + } + return nil +} + +func (x *BucketInfo) GetUnstakedAt() *timestamppb.Timestamp { + if x != nil { + return x.UnstakedAt + } + return nil +} + +func (x *BucketInfo) GetDelegate() string { + if x != nil { + return x.Delegate + } + return "" +} + +var File_blockindex_indexpb_liquidstaking_bucket_proto protoreflect.FileDescriptor + +var file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = []byte{ + 0x0a, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x70, 0x62, 0x2f, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x73, 0x74, 0x61, 0x6b, 0x69, + 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7e, 0x0a, 0x0a, 0x42, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0b, 0x61, + 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xbe, 0x01, 0x0a, 0x0a, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x79, 0x70, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x41, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, + 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescOnce sync.Once + file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData = file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc +) + +func file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP() []byte { + file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescOnce.Do(func() { + file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData = protoimpl.X.CompressGZIP(file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData) + }) + return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData +} + +var file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = []interface{}{ + (*BucketType)(nil), // 0: indexpb.BucketType + (*BucketInfo)(nil), // 1: indexpb.BucketInfo + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp +} +var file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = []int32{ + 2, // 0: indexpb.BucketType.activatedAt:type_name -> google.protobuf.Timestamp + 2, // 1: indexpb.BucketInfo.unlockedAt:type_name -> google.protobuf.Timestamp + 2, // 2: indexpb.BucketInfo.unstakedAt:type_name -> google.protobuf.Timestamp + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_blockindex_indexpb_liquidstaking_bucket_proto_init() } +func file_blockindex_indexpb_liquidstaking_bucket_proto_init() { + if File_blockindex_indexpb_liquidstaking_bucket_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes, + DependencyIndexes: file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs, + MessageInfos: file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes, + }.Build() + File_blockindex_indexpb_liquidstaking_bucket_proto = out.File + file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = nil + file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = nil + file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = nil +} diff --git a/blockindex/indexpb/liquidstaking_bucket.proto b/blockindex/indexpb/liquidstaking_bucket.proto new file mode 100644 index 0000000000..c62475b9f3 --- /dev/null +++ b/blockindex/indexpb/liquidstaking_bucket.proto @@ -0,0 +1,24 @@ +// Copyright (c) 2019 IoTeX +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +// To compile the proto, run: +// protoc --go_out=plugins=grpc:. *.proto +syntax = "proto3"; +package indexpb; +option go_package = "github.com/iotexproject/iotex-core/blockindex/indexpb"; +import "google/protobuf/timestamp.proto"; + +message BucketType { + string amount = 1; + uint64 duration = 2; + google.protobuf.Timestamp activatedAt = 3; +} + +message BucketInfo { + uint64 typeIndex = 1; + google.protobuf.Timestamp unlockedAt = 2; + google.protobuf.Timestamp unstakedAt = 3; + string delegate = 4; +} \ No newline at end of file diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go deleted file mode 100644 index e525b2b1dc..0000000000 --- a/blockindex/liquidstaking_cache.go +++ /dev/null @@ -1,57 +0,0 @@ -package blockindex - -import ( - "math/big" - "time" - - "github.com/iotexproject/iotex-core/db/batch" -) - -type ( - liquidStakingCache struct { - bucketMap map[uint64]*BucketInfo // map[token]bucketInfo - bucketTypes map[uint64]*BucketType - bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index - } -) - -func newLiquidStakingCache() *liquidStakingCache { - return &liquidStakingCache{ - bucketMap: make(map[uint64]*BucketInfo), - bucketTypes: make(map[uint64]*BucketType), - bucketTypeMap: make(map[int64]map[int64]uint64), - } -} - -func (s *liquidStakingCache) writeBatch(batch batch.KVStoreBatch) error { - // TODO (iip-13): index write batch - return nil -} - -func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { - s.bucketTypes[id] = bt - s.bucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id -} - -func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { - s.bucketMap[id] = bi -} - -func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - m, ok := s.bucketTypeMap[amount.Int64()] - if !ok { - return 0, false - } - id, ok := m[int64(duration)] - return id, ok -} - -func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.bucketTypes[id] - return bt, ok -} - -func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.bucketMap[id] - return bi, ok -} diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go new file mode 100644 index 0000000000..8919c2070c --- /dev/null +++ b/blockindex/liquidstaking_data.go @@ -0,0 +1,183 @@ +package blockindex + +import ( + "math/big" + "time" + + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/db/batch" + "github.com/pkg/errors" +) + +type ( + liquidStakingCache struct { + bucketMap map[uint64]*BucketInfo // map[token]BucketInfo + bucketTypes map[uint64]*BucketType + bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + } + + liquidStakingData struct { + dirty batch.CachedBatch // im-memory dirty data + dirtyCache *liquidStakingCache + clean db.KVStore // clean data in db + cleanCache *liquidStakingCache // in-memory index for clean data + } +) + +func newLiquidStakingCache() *liquidStakingCache { + return &liquidStakingCache{ + bucketMap: make(map[uint64]*BucketInfo), + bucketTypes: make(map[uint64]*BucketType), + bucketTypeMap: make(map[int64]map[int64]uint64), + } +} + +func (s *liquidStakingCache) writeBatch(batch batch.KVStoreBatch) error { + // TODO (iip-13): index write batch + return nil +} + +func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { + s.bucketTypes[id] = bt + s.bucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id +} + +func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { + s.bucketMap[id] = bi +} + +func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + m, ok := s.bucketTypeMap[amount.Int64()] + if !ok { + return 0, false + } + id, ok := m[int64(duration)] + return id, ok +} + +func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.bucketTypes[id] + return bt, ok +} + +func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.bucketMap[id] + return bi, ok +} + +func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { + data := liquidStakingData{ + dirty: batch.NewCachedBatch(), + clean: kvStore, + cleanCache: newLiquidStakingCache(), + dirtyCache: newLiquidStakingCache(), + } + return &data, nil +} + +func (s *liquidStakingData) loadCache() error { + ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) + if err != nil { + if !errors.Is(err, db.ErrNotExist) { + return err + } + } + for i := range vs { + var b BucketInfo + if err := b.deserialize(vs[i]); err != nil { + return err + } + s.cleanCache.putBucketInfo(deserializeUint64(ks[i]), &b) + } + + ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) + if err != nil { + if !errors.Is(err, db.ErrNotExist) { + return err + } + } + for i := range vs { + var b BucketType + if err := b.deserialize(vs[i]); err != nil { + return err + } + s.cleanCache.putBucketType(deserializeUint64(ks[i]), &b) + } + return nil +} + +func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) + if ok { + return id, true + } + id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) + return id, ok +} + +func (s *liquidStakingData) getBucketTypeCount() uint64 { + base := len(s.cleanCache.bucketTypes) + add := 0 + for k, dbt := range s.dirtyCache.bucketTypes { + _, ok := s.cleanCache.bucketTypes[k] + if dbt != nil && !ok { + add++ + } else if dbt == nil && ok { + add-- + } + } + return uint64(base + add) +} + +func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.dirtyCache.getBucketType(id) + if ok { + return bt, true + } + bt, ok = s.cleanCache.getBucketType(id) + return bt, ok +} + +func (s *liquidStakingData) putBucketType(id uint64, bt *BucketType) { + s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") + s.dirtyCache.putBucketType(id, bt) +} + +func (s *liquidStakingData) putBucketInfo(id uint64, bi *BucketInfo) { + s.dirty.Put(_liquidStakingBucketInfoNS, serializeUint64(id), bi.serialize(), "failed to put bucket info") + s.dirtyCache.putBucketInfo(id, bi) +} + +func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.dirtyCache.getBucketInfo(id) + if ok { + return bi, bi != nil + } + bi, ok = s.cleanCache.getBucketInfo(id) + return bi, ok +} + +func (s *liquidStakingData) burnBucket(id uint64) { + s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") + s.dirtyCache.putBucketInfo(id, nil) +} + +// GetBuckets(height uint64, offset, limit uint32) +// BucketsByVoter(voterAddr string, offset, limit uint32) +// BucketsByCandidate(candidateAddr string, offset, limit uint32) +// BucketByIndices(indecis []uint64) +// BucketCount() +// TotalStakingAmount() + +func (s *liquidStakingData) commit() error { + if err := s.cleanCache.writeBatch(s.dirty); err != nil { + return err + } + if err := s.clean.WriteBatch(s.dirty); err != nil { + return err + } + s.dirty.Lock() + s.dirty.ClearAndUnlock() + s.dirtyCache = newLiquidStakingCache() + return nil +} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 266ff4b027..fd102f9112 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -8,7 +8,6 @@ package blockindex import ( "context" "encoding/binary" - "encoding/json" "math/big" "strings" "time" @@ -19,12 +18,12 @@ import ( "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" - "github.com/iotexproject/iotex-core/db" - "github.com/iotexproject/iotex-core/db/batch" - "github.com/iotexproject/iotex-core/pkg/log" + "github.com/iotexproject/iotex-core/blockindex/indexpb" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" - "go.uber.org/zap" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" ) const ( @@ -99,13 +98,6 @@ type ( blockInterval time.Duration } - liquidStakingData struct { - dirty batch.CachedBatch // im-memory dirty data - dirtyCache *liquidStakingCache - clean db.KVStore // clean data in db - cleanCache *liquidStakingCache // in-memory index for clean data - } - // BucketInfo is the bucket information BucketInfo struct { TypeIndex uint64 @@ -327,7 +319,7 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { } newBtIdx, ok := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) + return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) } b.TypeIndex = newBtIdx b.UnlockedAt = nil @@ -508,141 +500,75 @@ func (e eventParam) fieldAddress(name string) (common.Address, error) { return eventField[common.Address](e, name) } -func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { - data := liquidStakingData{ - dirty: batch.NewCachedBatch(), - clean: kvStore, - cleanCache: newLiquidStakingCache(), - dirtyCache: newLiquidStakingCache(), +func (bt *BucketType) toProto() *indexpb.BucketType { + return &indexpb.BucketType{ + Amount: bt.Amount.String(), + Duration: uint64(bt.Duration), + ActivatedAt: timestamppb.New(*bt.ActivatedAt), } - return &data, nil } -func (s *liquidStakingData) loadCache() error { - ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrNotExist) { - return err - } - } - for i := range vs { - var b BucketInfo - if err := json.Unmarshal(vs[i], &b); err != nil { - return err - } - s.cleanCache.putBucketInfo(binary.LittleEndian.Uint64(ks[i]), &b) - } - - ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrNotExist) { - return err - } - } - for i := range vs { - var b BucketType - if err := json.Unmarshal(vs[i], &b); err != nil { - return err - } - s.cleanCache.putBucketType(binary.LittleEndian.Uint64(ks[i]), &b) +func (bt *BucketType) loadProto(p *indexpb.BucketType) error { + var ok bool + bt.Amount, ok = big.NewInt(0).SetString(p.Amount, 10) + if !ok { + return errors.New("failed to parse amount") } + bt.Duration = time.Duration(p.Duration) + t := p.ActivatedAt.AsTime() + bt.ActivatedAt = &t return nil } -func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) - if ok { - return id, true - } - id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) - return id, ok +func (bt *BucketType) serialize() []byte { + return byteutil.Must(proto.Marshal(bt.toProto())) } -func (s *liquidStakingData) getBucketTypeCount() uint64 { - base := len(s.cleanCache.bucketTypes) - add := 0 - for k, dbt := range s.dirtyCache.bucketTypes { - _, ok := s.cleanCache.bucketTypes[k] - if dbt != nil && !ok { - add++ - } else if dbt == nil && ok { - add-- - } +func (bt *BucketType) deserialize(b []byte) error { + m := indexpb.BucketType{} + if err := proto.Unmarshal(b, &m); err != nil { + return err } - return uint64(base + add) + return bt.loadProto(&m) } -func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.dirtyCache.getBucketType(id) - if ok { - return bt, true +func (bi *BucketInfo) toProto() *indexpb.BucketInfo { + return &indexpb.BucketInfo{ + TypeIndex: bi.TypeIndex, + UnlockedAt: timestamppb.New(*bi.UnlockedAt), + UnstakedAt: timestamppb.New(*bi.UnstakedAt), + Delegate: bi.Delegate, } - bt, ok = s.cleanCache.getBucketType(id) - return bt, ok } -func (s *liquidStakingData) putBucketType(id uint64, bt *BucketType) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, id) - s.dirty.Put(_liquidStakingBucketTypeNS, key, bt.serialize(), "failed to put bucket type") - s.dirtyCache.putBucketType(id, bt) -} - -func (s *liquidStakingData) putBucketInfo(id uint64, bi *BucketInfo) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, id) - s.dirty.Put(_liquidStakingBucketInfoNS, key, bi.serialize(), "failed to put bucket info") - s.dirtyCache.putBucketInfo(id, bi) +func (bi *BucketInfo) serialize() []byte { + return byteutil.Must(proto.Marshal(bi.toProto())) } -func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.dirtyCache.getBucketInfo(id) - if ok { - return bi, bi != nil +func (bi *BucketInfo) deserialize(b []byte) error { + m := indexpb.BucketInfo{} + if err := proto.Unmarshal(b, &m); err != nil { + return err } - bi, ok = s.cleanCache.getBucketInfo(id) - return bi, ok + return bi.loadProto(&m) } -func (s *liquidStakingData) burnBucket(id uint64) { - key := make([]byte, 8) - binary.LittleEndian.PutUint64(key, id) - s.dirty.Delete(_liquidStakingBucketInfoNS, key, "failed to delete bucket info") - s.dirtyCache.putBucketInfo(id, nil) -} - -// GetBuckets(height uint64, offset, limit uint32) -// BucketsByVoter(voterAddr string, offset, limit uint32) -// BucketsByCandidate(candidateAddr string, offset, limit uint32) -// BucketByIndices(indecis []uint64) -// BucketCount() -// TotalStakingAmount() - -func (s *liquidStakingData) commit() error { - if err := s.cleanCache.writeBatch(s.dirty); err != nil { - return err - } - if err := s.clean.WriteBatch(s.dirty); err != nil { - return err - } - s.dirty.Lock() - s.dirty.ClearAndUnlock() - s.dirtyCache = newLiquidStakingCache() +func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { + bi.TypeIndex = p.TypeIndex + t := p.UnlockedAt.AsTime() + bi.UnlockedAt = &t + t = p.UnstakedAt.AsTime() + bi.UnstakedAt = &t + bi.Delegate = p.Delegate return nil } -func (bt *BucketType) serialize() []byte { - b, err := json.Marshal(bt) - if err != nil { - log.S().Panic("marshal bucket type", zap.Error(err)) - } +func serializeUint64(v uint64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, v) return b } -func (bi *BucketInfo) serialize() []byte { - b, err := json.Marshal(bi) - if err != nil { - log.S().Panic("marshal bucket info", zap.Error(err)) - } - return b +func deserializeUint64(b []byte) uint64 { + return binary.LittleEndian.Uint64(b) } From 1e72ee34720b1470521b7018e98c9001b69ee5b8 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 25 Apr 2023 11:34:58 +0800 Subject: [PATCH 09/51] refactor --- blockindex/liquidstaking_data.go | 124 ++++++++++++++++++++++------ blockindex/liquidstaking_indexer.go | 106 +++++++++++++----------- chainservice/builder.go | 20 ++--- 3 files changed, 166 insertions(+), 84 deletions(-) diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index 8919c2070c..547be8eb2d 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -11,9 +11,10 @@ import ( type ( liquidStakingCache struct { - bucketMap map[uint64]*BucketInfo // map[token]BucketInfo - bucketTypes map[uint64]*BucketType - bucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo + candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket + idBucketTypeMap map[uint64]*BucketType + propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index } liquidStakingData struct { @@ -26,28 +27,72 @@ type ( func newLiquidStakingCache() *liquidStakingCache { return &liquidStakingCache{ - bucketMap: make(map[uint64]*BucketInfo), - bucketTypes: make(map[uint64]*BucketType), - bucketTypeMap: make(map[int64]map[int64]uint64), + idBucketMap: make(map[uint64]*BucketInfo), + idBucketTypeMap: make(map[uint64]*BucketType), + propertyBucketTypeMap: make(map[int64]map[int64]uint64), } } -func (s *liquidStakingCache) writeBatch(batch batch.KVStoreBatch) error { - // TODO (iip-13): index write batch +func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { + for i := 0; i < b.Size(); i++ { + write, err := b.Entry(i) + if err != nil { + return err + } + switch write.Namespace() { + case _liquidStakingBucketInfoNS: + if write.WriteType() == batch.Put { + var bi BucketInfo + if err = bi.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketInfo(id, &bi) + } else if write.WriteType() == batch.Delete { + id := deserializeUint64(write.Key()) + s.deleteBucketInfo(id) + } + case _liquidStakingBucketTypeNS: + if write.WriteType() == batch.Put { + var bt BucketType + if err = bt.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketType(id, &bt) + } + } + } return nil } func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { - s.bucketTypes[id] = bt - s.bucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id + s.idBucketTypeMap[id] = bt + s.propertyBucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id } func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { - s.bucketMap[id] = bi + s.idBucketMap[id] = bi + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) + } + s.candidateBucketMap[bi.Delegate][id] = true +} + +func (s *liquidStakingCache) deleteBucketInfo(id uint64) { + bi, ok := s.idBucketMap[id] + if !ok { + return + } + s.idBucketTypeMap[id] = nil + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + return + } + s.candidateBucketMap[bi.Delegate][id] = false } func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - m, ok := s.bucketTypeMap[amount.Int64()] + m, ok := s.propertyBucketTypeMap[amount.Int64()] if !ok { return 0, false } @@ -56,15 +101,42 @@ func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.D } func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.bucketTypes[id] + bt, ok := s.idBucketTypeMap[id] return bt, ok } +func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { + bt, ok := s.idBucketTypeMap[id] + if !ok { + panic("bucket type not found") + } + return bt +} + func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.bucketMap[id] + bi, ok := s.idBucketMap[id] return bi, ok } +func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { + votes := big.NewInt(0) + m, ok := s.candidateBucketMap[name] + if !ok { + return votes + } + for k, v := range m { + if v { + bi, ok := s.idBucketMap[k] + if !ok { + continue + } + bt := s.mustGetBucketType(bi.TypeIndex) + votes.Add(votes, bt.Amount) + } + } + return votes +} + func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { data := liquidStakingData{ dirty: batch.NewCachedBatch(), @@ -75,7 +147,7 @@ func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { return &data, nil } -func (s *liquidStakingData) loadCache() error { +func (s *liquidStakingIndexer) loadCache() error { ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { if !errors.Is(err, db.ErrNotExist) { @@ -106,7 +178,7 @@ func (s *liquidStakingData) loadCache() error { return nil } -func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { +func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) if ok { return id, true @@ -115,11 +187,11 @@ func (s *liquidStakingData) getBucketTypeIndex(amount *big.Int, duration time.Du return id, ok } -func (s *liquidStakingData) getBucketTypeCount() uint64 { - base := len(s.cleanCache.bucketTypes) +func (s *liquidStakingIndexer) getBucketTypeCount() uint64 { + base := len(s.cleanCache.idBucketTypeMap) add := 0 - for k, dbt := range s.dirtyCache.bucketTypes { - _, ok := s.cleanCache.bucketTypes[k] + for k, dbt := range s.dirtyCache.idBucketTypeMap { + _, ok := s.cleanCache.idBucketTypeMap[k] if dbt != nil && !ok { add++ } else if dbt == nil && ok { @@ -129,7 +201,7 @@ func (s *liquidStakingData) getBucketTypeCount() uint64 { return uint64(base + add) } -func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, bool) { +func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { bt, ok := s.dirtyCache.getBucketType(id) if ok { return bt, true @@ -138,17 +210,17 @@ func (s *liquidStakingData) getBucketType(id uint64) (*BucketType, bool) { return bt, ok } -func (s *liquidStakingData) putBucketType(id uint64, bt *BucketType) { +func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") s.dirtyCache.putBucketType(id, bt) } -func (s *liquidStakingData) putBucketInfo(id uint64, bi *BucketInfo) { +func (s *liquidStakingIndexer) putBucketInfo(id uint64, bi *BucketInfo) { s.dirty.Put(_liquidStakingBucketInfoNS, serializeUint64(id), bi.serialize(), "failed to put bucket info") s.dirtyCache.putBucketInfo(id, bi) } -func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, bool) { +func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { bi, ok := s.dirtyCache.getBucketInfo(id) if ok { return bi, bi != nil @@ -157,7 +229,7 @@ func (s *liquidStakingData) getBucketInfo(id uint64) (*BucketInfo, bool) { return bi, ok } -func (s *liquidStakingData) burnBucket(id uint64) { +func (s *liquidStakingIndexer) burnBucket(id uint64) { s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") s.dirtyCache.putBucketInfo(id, nil) } @@ -169,7 +241,7 @@ func (s *liquidStakingData) burnBucket(id uint64) { // BucketCount() // TotalStakingAmount() -func (s *liquidStakingData) commit() error { +func (s *liquidStakingIndexer) commit() error { if err := s.cleanCache.writeBatch(s.dirty); err != nil { return err } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index fd102f9112..a8327028f8 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -19,6 +19,8 @@ import ( "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/blockindex/indexpb" + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" @@ -74,13 +76,8 @@ const ( ]` // bucket related namespace in db - _liquidStakingBucketInfoNS = "lsbInfo" - _liquidStakingBucketTypeNS = "lsbType" - _liquidStakingBucketTypeMapNS = "lsbTypeMap" - _liquidStakingBucketTypeCountNS = "lsbTypeCount" - - // bucket cache size - _liquidStakingBucketCacheSize = 10000 + _liquidStakingBucketInfoNS = "lsbInfo" + _liquidStakingBucketTypeNS = "lsbType" ) type ( @@ -88,14 +85,15 @@ type ( LiquidStakingIndexer interface { blockdao.BlockIndexer - GetCandidateVotes(candidate string) (*big.Int, error) - GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) + GetCandidateVotes(candidate string) *big.Int } liquidStakingIndexer struct { - data *liquidStakingData - blockInterval time.Duration + dirty batch.CachedBatch // im-memory dirty data + dirtyCache *liquidStakingCache + clean db.KVStore // clean data in db + cleanCache *liquidStakingCache // in-memory index for clean data } // BucketInfo is the bucket information @@ -135,15 +133,27 @@ func init() { } // NewLiquidStakingIndexer creates a new liquid staking indexer -func NewLiquidStakingIndexer() *liquidStakingIndexer { - return &liquidStakingIndexer{} +func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) LiquidStakingIndexer { + return &liquidStakingIndexer{ + blockInterval: blockInterval, + dirty: batch.NewCachedBatch(), + dirtyCache: newLiquidStakingCache(), + clean: kvStore, + cleanCache: newLiquidStakingCache(), + } } func (s *liquidStakingIndexer) Start(ctx context.Context) error { - return nil + if err := s.clean.Start(ctx); err != nil { + return err + } + return s.loadCache() } func (s *liquidStakingIndexer) Stop(ctx context.Context) error { + if err := s.clean.Stop(ctx); err != nil { + return err + } return nil } @@ -161,7 +171,7 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } } } - return s.data.commit() + return s.commit() } func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { @@ -172,8 +182,8 @@ func (s *liquidStakingIndexer) Height() (uint64, error) { return 0, nil } -func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) (*big.Int, error) { - return nil, nil +func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { + return s.cleanCache.getCandidateVotes(candidate) } func (s *liquidStakingIndexer) GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) { @@ -238,11 +248,11 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, Duration: s.blockHeightToDuration(durationParam.Uint64()), ActivatedAt: &timeStamp, } - id, ok := s.data.getBucketTypeIndex(amountParam, bt.Duration) + id, ok := s.getBucketTypeIndex(amountParam, bt.Duration) if !ok { - id = s.data.getBucketTypeCount() + id = s.getBucketTypeCount() } - s.data.putBucketType(id, &bt) + s.putBucketType(id, &bt) return nil } @@ -256,16 +266,16 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return err } - id, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + id, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - bt, ok := s.data.getBucketType(id) + bt, ok := s.getBucketType(id) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } bt.ActivatedAt = nil - s.data.putBucketType(id, bt) + s.putBucketType(id, bt) return nil } @@ -287,7 +297,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { return err } - btIdx, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } @@ -295,7 +305,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { TypeIndex: btIdx, Delegate: string(delegateParam[:]), } - s.data.putBucketInfo(tokenIDParam.Uint64(), &bucket) + s.putBucketInfo(tokenIDParam.Uint64(), &bucket) return nil } @@ -309,21 +319,21 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.data.getBucketType(b.TypeIndex) + bt, ok := s.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := s.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) } b.TypeIndex = newBtIdx b.UnlockedAt = nil - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -333,12 +343,12 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnlockedAt = ×tamp - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -348,12 +358,12 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp t return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnstakedAt = ×tamp - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -372,20 +382,20 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } // merge to the first bucket - btIdx, ok := s.data.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - b, ok := s.data.getBucketInfo(tokenIDsParam[0].Uint64()) + b, ok := s.getBucketInfo(tokenIDsParam[0].Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx b.UnlockedAt = nil for i := 1; i < len(tokenIDsParam); i++ { - s.data.burnBucket(tokenIDsParam[i].Uint64()) + s.burnBucket(tokenIDsParam[i].Uint64()) } - s.data.putBucketInfo(tokenIDsParam[0].Uint64(), b) + s.putBucketInfo(tokenIDsParam[0].Uint64(), b) return nil } @@ -399,20 +409,20 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.data.getBucketType(b.TypeIndex) + bt, ok := s.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.data.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := s.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } b.TypeIndex = newBtIdx - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -426,20 +436,20 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.data.getBucketType(b.TypeIndex) + bt, ok := s.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.data.getBucketTypeIndex(amountParam, bt.Duration) + newBtIdx, ok := s.getBucketTypeIndex(amountParam, bt.Duration) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) } b.TypeIndex = newBtIdx - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -453,12 +463,12 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro return err } - b, ok := s.data.getBucketInfo(tokenIDParam.Uint64()) + b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.Delegate = string(delegateParam[:]) - s.data.putBucketInfo(tokenIDParam.Uint64(), b) + s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -468,7 +478,7 @@ func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { return err } - s.data.burnBucket(tokenIDParam.Uint64()) + s.burnBucket(tokenIDParam.Uint64()) return nil } diff --git a/chainservice/builder.go b/chainservice/builder.go index 9bf645c9ee..22443c2e31 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -240,11 +240,6 @@ func (builder *Builder) buildActionPool() error { return nil } -func (builder *Builder) buildSystemStakingIndexer() error { - builder.cs.liquidStakingIndexer = blockindex.NewLiquidStakingIndexer() - return nil -} - func (builder *Builder) buildBlockDAO(forTest bool) error { if builder.cs.blockdao != nil { return nil @@ -271,7 +266,7 @@ func (builder *Builder) buildBlockDAO(forTest bool) error { } func (builder *Builder) buildGatewayComponents(forTest bool) error { - indexer, bfIndexer, candidateIndexer, candBucketsIndexer, err := builder.createGateWayComponents(forTest) + indexer, bfIndexer, candidateIndexer, candBucketsIndexer, liquidStakeBucketsIndexer, err := builder.createGateWayComponents(forTest) if err != nil { return errors.Wrapf(err, "failed to create gateway components") } @@ -285,7 +280,10 @@ func (builder *Builder) buildGatewayComponents(forTest bool) error { } builder.cs.bfIndexer = bfIndexer builder.cs.indexer = indexer - + builder.cs.liquidStakingIndexer = liquidStakeBucketsIndexer + if builder.cs.liquidStakingIndexer != nil { + builder.cs.lifecycle.Add(builder.cs.liquidStakingIndexer) + } return nil } @@ -294,6 +292,7 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( bfIndexer blockindex.BloomFilterIndexer, candidateIndexer *poll.CandidateIndexer, candBucketsIndexer *staking.CandidatesBucketsIndexer, + liquidStakeBucketsIndexer blockindex.LiquidStakingIndexer, err error, ) { _, gateway := builder.cfg.Plugins[config.GatewayPlugin] @@ -317,6 +316,7 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( if builder.cfg.Chain.EnableStakingIndexer { candBucketsIndexer, err = staking.NewStakingCandidatesBucketsIndexer(db.NewMemKVStore()) } + liquidStakeBucketsIndexer = blockindex.NewLiquidStakingIndexer(db.NewMemKVStore(), builder.cfg.Genesis.BlockInterval) return } dbConfig := builder.cfg.DB @@ -345,6 +345,9 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( dbConfig.DbPath = builder.cfg.Chain.StakingIndexDBPath candBucketsIndexer, err = staking.NewStakingCandidatesBucketsIndexer(db.NewBoltDB(dbConfig)) } + + // create liquid staking indexer + liquidStakeBucketsIndexer = blockindex.NewLiquidStakingIndexer(db.NewBoltDB(dbConfig), builder.cfg.Genesis.BlockInterval) return } @@ -624,9 +627,6 @@ func (builder *Builder) build(forSubChain, forTest bool) (*ChainService, error) if err := builder.buildGatewayComponents(forTest); err != nil { return nil, err } - if err := builder.buildSystemStakingIndexer(); err != nil { - return nil, err - } if err := builder.buildBlockDAO(forTest); err != nil { return nil, err } From 8177ec6e448696fd5ad8630e458c2a4d1fe4f25a Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 25 Apr 2023 14:38:44 +0800 Subject: [PATCH 10/51] add GetBuckets --- blockindex/liquidstaking_data.go | 7 --- blockindex/liquidstaking_indexer.go | 77 +++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index 547be8eb2d..e44cbdfad6 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -234,13 +234,6 @@ func (s *liquidStakingIndexer) burnBucket(id uint64) { s.dirtyCache.putBucketInfo(id, nil) } -// GetBuckets(height uint64, offset, limit uint32) -// BucketsByVoter(voterAddr string, offset, limit uint32) -// BucketsByCandidate(candidateAddr string, offset, limit uint32) -// BucketByIndices(indecis []uint64) -// BucketCount() -// TotalStakingAmount() - func (s *liquidStakingIndexer) commit() error { if err := s.cleanCache.writeBatch(s.dirty); err != nil { return err diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index a8327028f8..683d1c1572 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -14,6 +14,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockchain/block" @@ -86,6 +88,7 @@ type ( blockdao.BlockIndexer GetCandidateVotes(candidate string) *big.Int + GetBuckets() ([]*staking.VoteBucket, error) } liquidStakingIndexer struct { @@ -99,9 +102,11 @@ type ( // BucketInfo is the bucket information BucketInfo struct { TypeIndex uint64 + CreatedAt time.Time UnlockedAt *time.Time UnstakedAt *time.Time Delegate string + Owner string } // BucketType is the bucket type @@ -158,15 +163,28 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { } func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { + actionMap := make(map[hash.Hash256]*action.SealedEnvelope) + for _, act := range blk.Actions { + h, err := act.Hash() + if err != nil { + return err + } + actionMap[h] = &act + } + for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue } + act, ok := actionMap[receipt.ActionHash] + if !ok { + return errors.Errorf("action %x not found", receipt.ActionHash) + } for _, log := range receipt.Logs() { if log.Address != LiquidStakingContractAddress { continue } - if err := s.handleEvent(ctx, blk, log); err != nil { + if err := s.handleEvent(ctx, blk, act, log); err != nil { return err } } @@ -186,11 +204,20 @@ func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { return s.cleanCache.getCandidateVotes(candidate) } -func (s *liquidStakingIndexer) GetBucket(bucketIndex uint64) (*staking.VoteBucket, error) { - return nil, nil +func (s *liquidStakingIndexer) GetBuckets() ([]*staking.VoteBucket, error) { + vbs := []*staking.VoteBucket{} + for id, bi := range s.cleanCache.idBucketMap { + bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) + vb, err := convertToVoteBucket(id, bi, bt) + if err != nil { + return nil, err + } + vbs = append(vbs, vb) + } + return vbs, nil } -func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block, log *action.Log) error { +func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) if err != nil { @@ -204,19 +231,20 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block } // handle different kinds of event + timestamp := blk.Timestamp() switch abiEvent.Name { case "BucketTypeActivated": - err = s.handleBucketTypeActivatedEvent(event, blk.Timestamp()) + err = s.handleBucketTypeActivatedEvent(event, timestamp) case "BucketTypeDeactivated": err = s.handleBucketTypeDeactivatedEvent(event) case "Staked": - err = s.handleStakedEvent(event) + err = s.handleStakedEvent(event, timestamp, act.SenderAddress()) case "Locked": err = s.handleLockedEvent(event) case "Unlocked": - err = s.handleUnlockedEvent(event, blk.Timestamp()) + err = s.handleUnlockedEvent(event, timestamp) case "Unstaked": - err = s.handleUnstakedEvent(event, blk.Timestamp()) + err = s.handleUnstakedEvent(event, timestamp) case "Merged": err = s.handleMergedEvent(event) case "DurationExtended": @@ -279,7 +307,7 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return nil } -func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp time.Time, owner address.Address) error { tokenIDParam, err := event.fieldUint256("tokenId") if err != nil { return err @@ -304,6 +332,8 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam) error { bucket := BucketInfo{ TypeIndex: btIdx, Delegate: string(delegateParam[:]), + Owner: owner.String(), + CreatedAt: timestamp, } s.putBucketInfo(tokenIDParam.Uint64(), &bucket) return nil @@ -582,3 +612,32 @@ func serializeUint64(v uint64) []byte { func deserializeUint64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } + +func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*staking.VoteBucket, error) { + var err error + vb := staking.VoteBucket{ + Index: token, + StakedAmount: bt.Amount, + StakedDuration: bt.Duration, + CreateTime: bi.CreatedAt, + StakeStartTime: bi.CreatedAt, + UnstakeStartTime: time.Unix(0, 0).UTC(), + AutoStake: bi.UnlockedAt == nil, + } + + vb.Candidate, err = address.FromString(bi.Delegate) + if err != nil { + return nil, err + } + vb.Owner, err = address.FromString(bi.Owner) + if err != nil { + return nil, err + } + if bi.UnlockedAt != nil { + vb.StakeStartTime = *bi.UnlockedAt + } + if bi.UnstakedAt != nil { + vb.UnstakeStartTime = *bi.UnstakedAt + } + return &vb, nil +} From 3772efa4d11b9cf9ca9ee8b5b7ac4744d1891add Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 25 Apr 2023 15:01:47 +0800 Subject: [PATCH 11/51] add real abi --- blockindex/liquidstaking_data.go | 30 + blockindex/liquidstaking_indexer.go | 1255 ++++++++++++++++++++++++++- 2 files changed, 1250 insertions(+), 35 deletions(-) diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index e44cbdfad6..6322a568e3 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -15,6 +15,7 @@ type ( candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket idBucketTypeMap map[uint64]*BucketType propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + height uint64 } liquidStakingData struct { @@ -30,6 +31,7 @@ func newLiquidStakingCache() *liquidStakingCache { idBucketMap: make(map[uint64]*BucketInfo), idBucketTypeMap: make(map[uint64]*BucketType), propertyBucketTypeMap: make(map[int64]map[int64]uint64), + candidateBucketMap: make(map[string]map[uint64]bool), } } @@ -66,6 +68,14 @@ func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { return nil } +func (s *liquidStakingCache) putHeight(h uint64) { + s.height = h +} + +func (s *liquidStakingCache) getHeight() uint64 { + return s.height +} + func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { s.idBucketTypeMap[id] = bt s.propertyBucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id @@ -148,6 +158,20 @@ func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { } func (s *liquidStakingIndexer) loadCache() error { + // load height + var height uint64 + h, err := s.clean.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) + if err != nil { + if !errors.Is(err, db.ErrNotExist) { + return err + } + height = 0 + } else { + height = deserializeUint64(h) + } + s.cleanCache.putHeight(height) + + // load bucket info ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { if !errors.Is(err, db.ErrNotExist) { @@ -162,6 +186,7 @@ func (s *liquidStakingIndexer) loadCache() error { s.cleanCache.putBucketInfo(deserializeUint64(ks[i]), &b) } + // load bucket type ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { if !errors.Is(err, db.ErrNotExist) { @@ -210,6 +235,11 @@ func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { return bt, ok } +func (s *liquidStakingIndexer) putHeight(h uint64) { + s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, serializeUint64(h), "failed to put height") + s.dirtyCache.putHeight(h) +} + func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") s.dirtyCache.putBucketType(id, bt) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 683d1c1572..5c61d97578 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -34,52 +34,1236 @@ const ( // TODO (iip-13): replace with the real liquid staking contract address LiquidStakingContractAddress = "" - // TODO (iip-13): replace with the real liquid staking contract ABI _liquidStakingContractABI = `[ { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "x", - "type": "uint256" - } - ], - "name": "Set", - "type": "event" + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" }, { - "inputs": [], - "name": "get", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes12", + "name": "oldDelegate", + "type": "bytes12" + }, + { + "indexed": true, + "internalType": "bytes12", + "name": "newDelegate", + "type": "bytes12" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "DurationExtended", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "FeeWithdrawal", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Locked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bytes12", + "name": "delegate", + "type": "bytes12" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unlocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "penaltyFee", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [], + "name": "UINT256_MAX", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "accumulatedWithdrawFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "activateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "addBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToUnstake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" }, { - "inputs": [ + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "bucketOf", + "outputs": [ + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unlockedAt_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unstakedAt_", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "delegate_", + "type": "bytes12" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + } + ], + "name": "bucketTypes", + "outputs": [ + { + "components": [ { - "internalType": "uint256", - "name": "x", - "type": "uint256" + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activatedAt", + "type": "uint256" } - ], - "name": "set", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + ], + "internalType": "struct BucketType[]", + "name": "types_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegates", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "deactivateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "emergencyWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "emergencyWithdrawPenaltyRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" + } + ], + "name": "extendDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newAmount", + "type": "uint256" + } + ], + "name": "increaseAmount", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "isActiveBucketType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "lockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfBucketTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_rate", + "type": "uint256" + } + ], + "name": "setEmergencyWithdrawPenaltyRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds_", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds_", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "unlockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdrawFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" } - ]` + ]` // bucket related namespace in db _liquidStakingBucketInfoNS = "lsbInfo" _liquidStakingBucketTypeNS = "lsbType" + _liquidStakingHeightNS = "lsHeight" ) type ( @@ -123,6 +1307,7 @@ type ( var ( _liquidStakingInterface abi.ABI + _liquidStakingHeightKey = []byte("lsHeight") errInvlidEventParam = errors.New("invalid event param") errBucketTypeNotExist = errors.New("bucket type does not exist") @@ -193,11 +1378,11 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { - return nil + return errors.New("not implemented") } func (s *liquidStakingIndexer) Height() (uint64, error) { - return 0, nil + return s.cleanCache.getHeight(), nil } func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { From 73dd9162e5a260f95c08869b692e4117a8987977 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 25 Apr 2023 21:46:41 +0800 Subject: [PATCH 12/51] refactor --- blockchain/config.go | 66 ++++----- blockchain/genesis/genesis.go | 2 +- blockindex/liquidstaking_data.go | 4 +- blockindex/liquidstaking_indexer.go | 6 +- blockindex/liquidstaking_indexer_test.go | 12 ++ chainservice/builder.go | 7 +- e2etest/contract_test.go | 163 ----------------------- e2etest/liquid_staking_test.go | 161 ++++++++++++++++++++++ 8 files changed, 217 insertions(+), 204 deletions(-) create mode 100644 blockindex/liquidstaking_indexer_test.go delete mode 100644 e2etest/contract_test.go create mode 100644 e2etest/liquid_staking_test.go diff --git a/blockchain/config.go b/blockchain/config.go index cabaeb2252..042e03dcff 100644 --- a/blockchain/config.go +++ b/blockchain/config.go @@ -24,23 +24,24 @@ import ( type ( // Config is the config struct for blockchain package Config struct { - ChainDBPath string `yaml:"chainDBPath"` - TrieDBPatchFile string `yaml:"trieDBPatchFile"` - TrieDBPath string `yaml:"trieDBPath"` - StakingPatchDir string `yaml:"stakingPatchDir"` - IndexDBPath string `yaml:"indexDBPath"` - BloomfilterIndexDBPath string `yaml:"bloomfilterIndexDBPath"` - CandidateIndexDBPath string `yaml:"candidateIndexDBPath"` - StakingIndexDBPath string `yaml:"stakingIndexDBPath"` - ID uint32 `yaml:"id"` - EVMNetworkID uint32 `yaml:"evmNetworkID"` - Address string `yaml:"address"` - ProducerPrivKey string `yaml:"producerPrivKey"` - ProducerPrivKeySchema string `yaml:"producerPrivKeySchema"` - SignatureScheme []string `yaml:"signatureScheme"` - EmptyGenesis bool `yaml:"emptyGenesis"` - GravityChainDB db.Config `yaml:"gravityChainDB"` - Committee committee.Config `yaml:"committee"` + ChainDBPath string `yaml:"chainDBPath"` + TrieDBPatchFile string `yaml:"trieDBPatchFile"` + TrieDBPath string `yaml:"trieDBPath"` + StakingPatchDir string `yaml:"stakingPatchDir"` + IndexDBPath string `yaml:"indexDBPath"` + BloomfilterIndexDBPath string `yaml:"bloomfilterIndexDBPath"` + CandidateIndexDBPath string `yaml:"candidateIndexDBPath"` + StakingIndexDBPath string `yaml:"stakingIndexDBPath"` + LiquidStakingIndexDBPath string `yaml:"liquidStakingIndexDBPath"` + ID uint32 `yaml:"id"` + EVMNetworkID uint32 `yaml:"evmNetworkID"` + Address string `yaml:"address"` + ProducerPrivKey string `yaml:"producerPrivKey"` + ProducerPrivKeySchema string `yaml:"producerPrivKeySchema"` + SignatureScheme []string `yaml:"signatureScheme"` + EmptyGenesis bool `yaml:"emptyGenesis"` + GravityChainDB db.Config `yaml:"gravityChainDB"` + Committee committee.Config `yaml:"committee"` EnableTrielessStateDB bool `yaml:"enableTrielessStateDB"` // EnableStateDBCaching enables cachedStateDBOption @@ -75,21 +76,22 @@ type ( var ( // DefaultConfig is the default config of chain DefaultConfig = Config{ - ChainDBPath: "/var/data/chain.db", - TrieDBPatchFile: "/var/data/trie.db.patch", - TrieDBPath: "/var/data/trie.db", - StakingPatchDir: "/var/data", - IndexDBPath: "/var/data/index.db", - BloomfilterIndexDBPath: "/var/data/bloomfilter.index.db", - CandidateIndexDBPath: "/var/data/candidate.index.db", - StakingIndexDBPath: "/var/data/staking.index.db", - ID: 1, - EVMNetworkID: 4689, - Address: "", - ProducerPrivKey: generateRandomKey(SigP256k1), - SignatureScheme: []string{SigP256k1}, - EmptyGenesis: false, - GravityChainDB: db.Config{DbPath: "/var/data/poll.db", NumRetries: 10}, + ChainDBPath: "/var/data/chain.db", + TrieDBPatchFile: "/var/data/trie.db.patch", + TrieDBPath: "/var/data/trie.db", + StakingPatchDir: "/var/data", + IndexDBPath: "/var/data/index.db", + BloomfilterIndexDBPath: "/var/data/bloomfilter.index.db", + CandidateIndexDBPath: "/var/data/candidate.index.db", + StakingIndexDBPath: "/var/data/staking.index.db", + LiquidStakingIndexDBPath: "/var/data/liquidstaking.index.db", + ID: 1, + EVMNetworkID: 4689, + Address: "", + ProducerPrivKey: generateRandomKey(SigP256k1), + SignatureScheme: []string{SigP256k1}, + EmptyGenesis: false, + GravityChainDB: db.Config{DbPath: "/var/data/poll.db", NumRetries: 10}, Committee: committee.Config{ GravityChainAPIs: []string{}, }, diff --git a/blockchain/genesis/genesis.go b/blockchain/genesis/genesis.go index 760bc62ef6..98a23d5d66 100644 --- a/blockchain/genesis/genesis.go +++ b/blockchain/genesis/genesis.go @@ -44,7 +44,7 @@ func defaultConfig() Genesis { Blockchain: Blockchain{ Timestamp: 1546329600, BlockGasLimit: 20000000, - ActionGasLimit: 5000000, + ActionGasLimit: 50000000, BlockInterval: 10 * time.Second, NumSubEpochs: 2, DardanellesNumSubEpochs: 30, diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index 6322a568e3..52b5bd2c9e 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -174,7 +174,7 @@ func (s *liquidStakingIndexer) loadCache() error { // load bucket info ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { - if !errors.Is(err, db.ErrNotExist) { + if !errors.Is(err, db.ErrBucketNotExist) { return err } } @@ -189,7 +189,7 @@ func (s *liquidStakingIndexer) loadCache() error { // load bucket type ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { - if !errors.Is(err, db.ErrNotExist) { + if !errors.Is(err, db.ErrBucketNotExist) { return err } } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 5c61d97578..d237362fa5 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -33,8 +33,8 @@ import ( const ( // TODO (iip-13): replace with the real liquid staking contract address LiquidStakingContractAddress = "" - - _liquidStakingContractABI = `[ + // LiquidStakingContractABI is the ABI of liquid staking contract + LiquidStakingContractABI = `[ { "inputs": [], "stateMutability": "nonpayable", @@ -1316,7 +1316,7 @@ var ( func init() { var err error - _liquidStakingInterface, err = abi.JSON(strings.NewReader(_liquidStakingContractABI)) + _liquidStakingInterface, err = abi.JSON(strings.NewReader(LiquidStakingContractABI)) if err != nil { panic(err) } diff --git a/blockindex/liquidstaking_indexer_test.go b/blockindex/liquidstaking_indexer_test.go new file mode 100644 index 0000000000..a7d9015130 --- /dev/null +++ b/blockindex/liquidstaking_indexer_test.go @@ -0,0 +1,12 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import "testing" + +func TestLiquidStakingIndexer(t *testing.T) { + +} diff --git a/chainservice/builder.go b/chainservice/builder.go index 22443c2e31..be5aa0cf40 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -281,9 +281,9 @@ func (builder *Builder) buildGatewayComponents(forTest bool) error { builder.cs.bfIndexer = bfIndexer builder.cs.indexer = indexer builder.cs.liquidStakingIndexer = liquidStakeBucketsIndexer - if builder.cs.liquidStakingIndexer != nil { - builder.cs.lifecycle.Add(builder.cs.liquidStakingIndexer) - } + // if builder.cs.liquidStakingIndexer != nil { + // builder.cs.lifecycle.Add(builder.cs.liquidStakingIndexer) + // } return nil } @@ -347,6 +347,7 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( } // create liquid staking indexer + dbConfig.DbPath = builder.cfg.Chain.LiquidStakingIndexDBPath liquidStakeBucketsIndexer = blockindex.NewLiquidStakingIndexer(db.NewBoltDB(dbConfig), builder.cfg.Genesis.BlockInterval) return } diff --git a/e2etest/contract_test.go b/e2etest/contract_test.go deleted file mode 100644 index 8e56b49f53..0000000000 --- a/e2etest/contract_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package e2etest - -import ( - "context" - "encoding/hex" - "math/big" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/iotexproject/go-pkgs/hash" - "github.com/iotexproject/iotex-core/action" - "github.com/iotexproject/iotex-core/action/protocol" - "github.com/iotexproject/iotex-core/blockchain/genesis" - "github.com/iotexproject/iotex-core/config" - "github.com/iotexproject/iotex-core/pkg/unit" - "github.com/iotexproject/iotex-core/server/itx" - "github.com/iotexproject/iotex-core/state" - "github.com/iotexproject/iotex-core/test/identityset" - "github.com/iotexproject/iotex-core/testutil" - "github.com/stretchr/testify/require" -) - -func TestContract(t *testing.T) { - require := require.New(t) - - testReadContract := func(cfg config.Config, t *testing.T) { - ctx := context.Background() - - // Create a new blockchain - svr, err := itx.NewServer(cfg) - require.NoError(err) - require.NoError(svr.Start(ctx)) - defer func() { - require.NoError(svr.Stop(ctx)) - }() - - chainID := cfg.Chain.ID - bc := svr.ChainService(chainID).Blockchain() - sf := svr.ChainService(chainID).StateFactory() - ap := svr.ChainService(chainID).ActionPool() - dao := svr.ChainService(chainID).BlockDAO() - registry := svr.ChainService(chainID).Registry() - require.NotNil(bc) - require.NotNil(registry) - admin := identityset.PrivateKey(26) - state0 := hash.BytesToHash160(identityset.Address(26).Bytes()) - s := &state.Account{} - _, err = sf.State(s, protocol.LegacyKeyOption(state0)) - require.NoError(err) - require.Equal(unit.ConvertIotxToRau(100000000), s.Balance) - - // deploy staking contract - data, _ := hex.DecodeString("608060405234801561001057600080fd5b50610187806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806360fe47b11461003b5780636d4ce63c14610057575b600080fd5b610055600480360381019061005091906100fa565b610075565b005b61005f6100b6565b60405161006c9190610136565b60405180910390f35b806000819055507fdf7a95aebff315db1b7716215d602ab537373cdb769232aae6055c06e798425b816040516100ab9190610136565b60405180910390a150565b60008054905090565b600080fd5b6000819050919050565b6100d7816100c4565b81146100e257600080fd5b50565b6000813590506100f4816100ce565b92915050565b6000602082840312156101105761010f6100bf565b5b600061011e848285016100e5565b91505092915050565b610130816100c4565b82525050565b600060208201905061014b6000830184610127565b9291505056fea2646970667358221220f5056e078d0c1d02dd0cbf9d99c912c45a3d2078427fcf18f7f7eb1b15b263fb64736f6c63430008110033") - fixedTime := time.Unix(cfg.Genesis.Timestamp, 0) - ex, err := action.SignedExecution(action.EmptyAddress, admin, 1, big.NewInt(0), 10000000, big.NewInt(testutil.TestGasPriceInt64), data) - require.NoError(err) - - deployHash, err := ex.Hash() - require.NoError(err) - require.NoError(ap.Add(context.Background(), ex)) - blk, err := bc.MintNewBlock(fixedTime) - require.NoError(err) - require.NoError(bc.CommitBlock(blk)) - r, err := dao.GetReceiptByActionHash(deployHash, 1) - require.NoError(err) - require.Equal(r.ContractAddress, "io123vqxxup8n3ld8jygvx729r6295pv9krjn2tjh") - - // set value - _abi := `[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"x","type":"uint256"}],"name":"Set","type":"event"},{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}]` - contractABI, err := abi.JSON(strings.NewReader(_abi)) - require.NoError(err) - fixedAmount := unit.ConvertIotxToRau(200) - sk := identityset.PrivateKey(26) - nonce := uint64(0) - data, err = contractABI.Pack("set", big.NewInt(10)) - require.NoError(err) - require.True(len(data) > 0) - ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) - require.NoError(err) - require.NoError(ap.Add(context.Background(), ex)) - // data, err = contractABI.Pack("get") - // require.NoError(err) - // require.True(len(data) > 0) - // ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) - // require.NoError(err) - // require.NoError(ap.Add(context.Background(), ex)) - blk, err = bc.MintNewBlock(fixedTime) - require.NoError(err) - require.NoError(bc.CommitBlock(blk)) - } - - cfg := config.Default - testTriePath, err := testutil.PathOfTempFile("trie") - require.NoError(err) - testDBPath, err := testutil.PathOfTempFile("db") - require.NoError(err) - testIndexPath, err := testutil.PathOfTempFile("index") - require.NoError(err) - testBloomfilterIndexPath, err := testutil.PathOfTempFile("bloomfilterindex") - require.NoError(err) - testCandidateIndexPath, err := testutil.PathOfTempFile("candidateindex") - require.NoError(err) - testSystemLogPath, err := testutil.PathOfTempFile("systemlog") - require.NoError(err) - testConsensusPath, err := testutil.PathOfTempFile("consensus") - require.NoError(err) - defer func() { - testutil.CleanupPath(testTriePath) - testutil.CleanupPath(testDBPath) - testutil.CleanupPath(testIndexPath) - testutil.CleanupPath(testBloomfilterIndexPath) - testutil.CleanupPath(testCandidateIndexPath) - testutil.CleanupPath(testSystemLogPath) - testutil.CleanupPath(testConsensusPath) - // clear the gateway - delete(cfg.Plugins, config.GatewayPlugin) - }() - - cfg.ActPool.MinGasPriceStr = "0" - cfg.Chain.TrieDBPatchFile = "" - cfg.Chain.TrieDBPath = testTriePath - cfg.Chain.ChainDBPath = testDBPath - cfg.Chain.IndexDBPath = testIndexPath - cfg.Chain.BloomfilterIndexDBPath = testBloomfilterIndexPath - cfg.Chain.CandidateIndexDBPath = testCandidateIndexPath - cfg.System.SystemLogDBPath = testSystemLogPath - cfg.Consensus.RollDPoS.ConsensusDBPath = testConsensusPath - cfg.Chain.ProducerPrivKey = "a000000000000000000000000000000000000000000000000000000000000000" - cfg.Consensus.Scheme = config.RollDPoSScheme - // cfg.Genesis.Blockchain = genesis.Blockchain{ - // Timestamp: config.Default.Genesis.Timestamp, - // BlockGasLimit: config.Default.Genesis.BlockGasLimit, - // ActionGasLimit: config.Default.Genesis.ActionGasLimit, - // BlockInterval: config.Default.Genesis.BlockInterval, - // NumSubEpochs: uint64(config.Default.Genesis.NumSubEpochs), - // DardanellesNumSubEpochs: uint64(config.Default.Genesis.DardanellesNumSubEpochs), - // NumDelegates: uint64(config.Default.Genesis.NumDelegates), - // NumCandidateDelegates: uint64(config.Default.Genesis.NumCandidateDelegates), - // TimeBasedRotation: config.Default.Genesis.TimeBasedRotation, - // } - cfg.Genesis.NumDelegates = 1 - cfg.Genesis.NumSubEpochs = 10 - cfg.Genesis.Delegates = []genesis.Delegate{ - { - OperatorAddrStr: identityset.Address(0).String(), - RewardAddrStr: identityset.Address(0).String(), - VotesStr: "10", - }, - } - cfg.Genesis.PollMode = "lifeLong" - cfg.Genesis.EnableGravityChainVoting = false - cfg.Plugins[config.GatewayPlugin] = true - cfg.Chain.EnableAsyncIndexWrite = false - cfg.Genesis.AleutianBlockHeight = 2 - cfg.Genesis.BeringBlockHeight = 0 - cfg.Genesis.HawaiiBlockHeight = 0 - - t.Run("test read staking contract", func(t *testing.T) { - testReadContract(cfg, t) - }) -} diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go new file mode 100644 index 0000000000..eedc18d704 --- /dev/null +++ b/e2etest/liquid_staking_test.go @@ -0,0 +1,161 @@ +package e2etest + +import ( + "context" + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-core/action" + "github.com/iotexproject/iotex-core/action/protocol" + "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/config" + "github.com/iotexproject/iotex-core/pkg/unit" + "github.com/iotexproject/iotex-core/server/itx" + "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 ( + _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b506040518060400160405280600981526020017f4275636b65744e465400000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f424b54000000000000000000000000000000000000000000000000000000000081525081600090816200008f91906200042d565b508060019081620000a191906200042d565b505050620000c4620000b8620000e560201b60201c565b620000ed60201b60201c565b6000600660146101000a81548160ff02191690831515021790555062000514565b600033905090565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200023557607f821691505b6020821081036200024b576200024a620001ed565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620002b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000276565b620002c1868362000276565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200030e620003086200030284620002d9565b620002e3565b620002d9565b9050919050565b6000819050919050565b6200032a83620002ed565b62000342620003398262000315565b84845462000283565b825550505050565b600090565b620003596200034a565b620003668184846200031f565b505050565b5b818110156200038e57620003826000826200034f565b6001810190506200036c565b5050565b601f821115620003dd57620003a78162000251565b620003b28462000266565b81016020851015620003c2578190505b620003da620003d18562000266565b8301826200036b565b50505b505050565b600082821c905092915050565b60006200040260001984600802620003e2565b1980831691505092915050565b60006200041d8383620003ef565b9150826002028217905092915050565b6200043882620001b3565b67ffffffffffffffff811115620004545762000453620001be565b5b6200046082546200021c565b6200046d82828562000392565b600060209050601f831160018114620004a5576000841562000490578287015190505b6200049c85826200040f565b8655506200050c565b601f198416620004b58662000251565b60005b82811015620004df57848901518255600182019150602085019450602081019050620004b8565b86831015620004ff5784890151620004fb601f891682620003ef565b8355505b6001600288020188555050505b505050505050565b61700c80620005246000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf14610a16578063e449f34114610a3f578063e985e9c514610a68578063eb0ffb2e14610aa5578063f0b56b5d14610ace578063f2fde38b14610af957610292565b8063c87b56dd146108fc578063c8e7792314610939578063cd0a02d014610962578063d0949f9914610992578063d6605fd8146109bd578063d6819bcc146109e657610292565b8063a22cb46511610113578063a22cb46514610820578063ad46fc6414610849578063b2383e5514610872578063b88d4fde1461088e578063b8f4bd7b146108b7578063bbe33ea5146108e057610292565b806378bfca101461070e5780638456cb591461074b5780638da5cb5b1461076257806393b6ef591461078d57806395d89b41146107ca5780639f7d5b00146107f557610292565b806342842e0e116101fe5780635d36598f116101b75780635d36598f146105ee5780636198e339146106175780636352211e146106405780636faa5c271461067d57806370a08231146106ba578063715018a6146106f757610292565b806342842e0e146104c3578063431cd92a146104ec57806343e06c591461052d578063597cc14a1461056a5780635c975abb1461059a5780635ceb8b5b146105c557610292565b80631338736f116102505780631338736f146103cb57806323b872dd146103f45780632dc830081461041d5780632e17de78146104465780633f4ba83a1461046f5780633fac69af1461048657610292565b8062f714ce1461029757806301ffc9a7146102c057806303459b16146102fd57806306fdde031461033a578063081812fc14610365578063095ea7b3146103a2575b600080fd5b3480156102a357600080fd5b506102be60048036038101906102b99190614f10565b610b22565b005b3480156102cc57600080fd5b506102e760048036038101906102e29190614fa8565b610bf7565b6040516102f49190614ff0565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f919061500b565b610cd9565b6040516103319190615047565b60405180910390f35b34801561034657600080fd5b5061034f610d0a565b60405161035c91906150f2565b60405180910390f35b34801561037157600080fd5b5061038c6004803603810190610387919061500b565b610d9c565b6040516103999190615135565b60405180910390f35b3480156103ae57600080fd5b506103c960048036038101906103c4919061517c565b610de2565b005b3480156103d757600080fd5b506103f260048036038101906103ed91906151bc565b610ef9565b005b34801561040057600080fd5b5061041b600480360381019061041691906151fc565b610f73565b005b34801561042957600080fd5b50610444600480360381019061043f91906152a7565b610fd3565b005b34801561045257600080fd5b5061046d6004803603810190610468919061500b565b61103e565b005b34801561047b57600080fd5b506104846110f6565b005b34801561049257600080fd5b506104ad60048036038101906104a8919061534c565b611108565b6040516104ba9190615519565b60405180910390f35b3480156104cf57600080fd5b506104ea60048036038101906104e591906151fc565b6112cb565b005b3480156104f857600080fd5b50610513600480360381019061050e919061500b565b6112eb565b60405161052495949392919061554a565b60405180910390f35b34801561053957600080fd5b50610554600480360381019061054f91906151bc565b611378565b6040516105619190614ff0565b60405180910390f35b610584600480360381019061057f91906152a7565b611394565b6040516105919190615047565b60405180910390f35b3480156105a657600080fd5b506105af611413565b6040516105bc9190614ff0565b60405180910390f35b3480156105d157600080fd5b506105ec60048036038101906105e791906155f3565b61142a565b005b3480156105fa57600080fd5b5061061560048036038101906106109190615653565b6114e0565b005b34801561062357600080fd5b5061063e6004803603810190610639919061500b565b611589565b005b34801561064c57600080fd5b506106676004803603810190610662919061500b565b6115f6565b6040516106749190615135565b60405180910390f35b34801561068957600080fd5b506106a4600480360381019061069f919061534c565b61167c565b6040516106b19190615519565b60405180910390f35b3480156106c657600080fd5b506106e160048036038101906106dc91906156a0565b61183f565b6040516106ee9190615047565b60405180910390f35b34801561070357600080fd5b5061070c6118f6565b005b34801561071a57600080fd5b50610735600480360381019061073091906151bc565b61190a565b60405161074291906157be565b60405180910390f35b34801561075757600080fd5b50610760611a50565b005b34801561076e57600080fd5b50610777611a62565b6040516107849190615135565b60405180910390f35b34801561079957600080fd5b506107b460048036038101906107af919061500b565b611a8c565b6040516107c19190615047565b60405180910390f35b3480156107d657600080fd5b506107df611ac8565b6040516107ec91906150f2565b60405180910390f35b34801561080157600080fd5b5061080a611b5a565b6040516108179190615047565b60405180910390f35b34801561082c57600080fd5b506108476004803603810190610842919061580c565b611b67565b005b34801561085557600080fd5b50610870600480360381019061086b919061584c565b611b7d565b005b61088c600480360381019061088791906151bc565b611c28565b005b34801561089a57600080fd5b506108b560048036038101906108b091906159dc565b611dfc565b005b3480156108c357600080fd5b506108de60048036038101906108d99190615a5f565b611e5e565b005b6108fa60048036038101906108f591906155f3565b611f6f565b005b34801561090857600080fd5b50610923600480360381019061091e919061500b565b6122e9565b60405161093091906150f2565b60405180910390f35b34801561094557600080fd5b50610960600480360381019061095b91906151bc565b612351565b005b61097c60048036038101906109779190615abf565b6124d4565b6040516109899190615047565b60405180910390f35b34801561099e57600080fd5b506109a76125cc565b6040516109b49190615047565b60405180910390f35b3480156109c957600080fd5b506109e460048036038101906109df91906151bc565b6125f0565b005b610a0060048036038101906109fb9190615be9565b6127b9565b604051610a0d9190615047565b60405180910390f35b348015610a2257600080fd5b50610a3d6004803603810190610a3891906151bc565b6128da565b005b348015610a4b57600080fd5b50610a666004803603810190610a619190615653565b612952565b005b348015610a7457600080fd5b50610a8f6004803603810190610a8a9190615c58565b612a46565b604051610a9c9190614ff0565b60405180910390f35b348015610ab157600080fd5b50610acc6004803603810190610ac791906151bc565b612ada565b005b348015610ada57600080fd5b50610ae3612b72565b604051610af09190615047565b60405180910390f35b348015610b0557600080fd5b50610b206004803603810190610b1b91906156a0565b612b78565b005b610b2a612bfb565b81610b3481612c45565b60006008600085815260200190815260200160002090506000610b5a8260020154612cbe565b14610b9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b9190615ce4565b60405180910390fd5b610ba384612d37565b610bad8184612e85565b8273ffffffffffffffffffffffffffffffffffffffff16847fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee60405160405180910390a350505050565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610cc257507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610cd25750610cd182612f65565b5b9050919050565b6000610ce482612fcf565b610d036008600084815260200190815260200160002060020154612cbe565b9050919050565b606060008054610d1990615d33565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4590615d33565b8015610d925780601f10610d6757610100808354040283529160200191610d92565b820191906000526020600020905b815481529060010190602001808311610d7557829003601f168201915b5050505050905090565b6000610da78261301a565b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610ded826115f6565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e5490615dd6565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e7c613065565b73ffffffffffffffffffffffffffffffffffffffff161480610eab5750610eaa81610ea5613065565b612a46565b5b610eea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ee190615e68565b60405180910390fd5b610ef4838361306d565b505050565b610f01612bfb565b81610f0b81612c45565b6000600860008581526020019081526020016000209050610f2b81613126565b610f358184613176565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610f659190615047565b60405180910390a250505050565b610f84610f7e613065565b826133b7565b610fc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fba90615efa565b60405180910390fd5b610fce83838361344c565b505050565b610fdb612bfb565b81610fe581612c45565b6110016008600085815260200190815260200160002083613745565b827ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c836040516110319190615f1a565b60405180910390a2505050565b611046612bfb565b8061105081612c45565b600060086000848152602001908152602001600020905061107081613126565b600061107b82613ae7565b146110bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b290615f81565b60405180910390fd5b6110c481613b91565b827f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b260405160405180910390a2505050565b6110fe613c78565b611106613cf6565b565b60608282905067ffffffffffffffff811115611127576111266158b1565b5b60405190808252806020026020018201604052801561115a57816020015b60608152602001906001900390816111455790505b5090506000611167611b5a565b905060005b848490508110156112c3578167ffffffffffffffff811115611191576111906158b1565b5b6040519080825280602002602001820160405280156111bf5781602001602082028036833780820191505090505b508382815181106111d3576111d2615fa1565b5b60200260200101819052506000600960008787858181106111f7576111f6615fa1565b5b905060200201602081019061120c9190615fd0565b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020905060005b838110156112b1578160008281526020019081526020016000205485848151811061127b5761127a615fa1565b5b6020026020010151828151811061129557611294615fa1565b5b6020026020010181815250506112aa81613d59565b905061124d565b50506112bc81613d59565b905061116c565b505092915050565b6112e683838360405180602001604052806000815250611dfc565b505050565b60008060008060006112fc86612fcf565b60006008600088815260200190815260200160002090506000600b82600001548154811061132d5761132c615fa1565b5b9060005260206000209060030201905080600001548160010154836001015484600201548560030160009054906101000a900460a01b96509650965096509650505091939590929450565b600061138c6113878484613d66565b613de5565b905092915050565b600061139e612bfb565b600034905060006113af8286613d66565b90506113ba81613e17565b6113c48185613e62565b60006007549050807f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8685896040516113ff93929190615ffd565b60405180910390a280935050505092915050565b6000600660149054906101000a900460ff16905090565b611432612bfb565b60008060005b858590508110156114d85785858281811061145657611455615fa1565b5b90506020020135925061146883612c45565b60086000848152602001908152602001600020915061148682613126565b6114908285613176565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516114c09190615047565b60405180910390a26114d181613d59565b9050611438565b505050505050565b6114e8612bfb565b60008060005b848490508110156115825784848281811061150c5761150b615fa1565b5b90506020020135925061151e83612c45565b60086000848152602001908152602001600020915061153c8261400e565b6115458261405e565b827ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184260405160405180910390a261157b81613d59565b90506114ee565b5050505050565b611591612bfb565b8061159b81612c45565b60006008600084815260200190815260200160002090506115bb8161400e565b6115c48161405e565b827ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184260405160405180910390a2505050565b600080611602836141ed565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161166a90616080565b60405180910390fd5b80915050919050565b60608282905067ffffffffffffffff81111561169b5761169a6158b1565b5b6040519080825280602002602001820160405280156116ce57816020015b60608152602001906001900390816116b95790505b50905060006116db611b5a565b905060005b84849050811015611837578167ffffffffffffffff811115611705576117046158b1565b5b6040519080825280602002602001820160405280156117335781602001602082028036833780820191505090505b5083828151811061174757611746615fa1565b5b60200260200101819052506000600a600087878581811061176b5761176a615fa1565b5b90506020020160208101906117809190615fd0565b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020905060005b8381101561182557816000828152602001908152602001600020548584815181106117ef576117ee615fa1565b5b6020026020010151828151811061180957611808615fa1565b5b60200260200101818152505061181e81613d59565b90506117c1565b505061183081613d59565b90506116e0565b505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036118af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a690616112565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6118fe613c78565b611908600061422a565b565b606060008211801561192e575061191f611b5a565b828461192b9190616161565b11155b61196d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611964906161e1565b60405180910390fd5b8167ffffffffffffffff811115611987576119866158b1565b5b6040519080825280602002602001820160405280156119c057816020015b6119ad614e47565b8152602001906001900390816119a55790505b50905060005b82811015611a4957600b818501815481106119e4576119e3615fa1565b5b90600052602060002090600302016040518060600160405290816000820154815260200160018201548152602001600282015481525050828281518110611a2e57611a2d615fa1565b5b6020026020010181905250611a4281613d59565b90506119c6565b5092915050565b611a58613c78565b611a606142f0565b565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000611a9782612fcf565b6000600860008481526020019081526020016000209050611ab781613126565b611ac081613ae7565b915050919050565b606060018054611ad790615d33565b80601f0160208091040260200160405190810160405280929190818152602001828054611b0390615d33565b8015611b505780601f10611b2557610100808354040283529160200191611b50565b820191906000526020600020905b815481529060010190602001808311611b3357829003601f168201915b5050505050905090565b6000600b80549050905090565b611b79611b72613065565b8383614353565b5050565b611b85612bfb565b600080600090505b84849050811015611c2157848482818110611bab57611baa615fa1565b5b905060200201359150611bbd82612c45565b611bd96008600084815260200190815260200160002084613745565b817ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c84604051611c099190615f1a565b60405180910390a2611c1a81613d59565b9050611b8d565b5050505050565b611c30612bfb565b81611c3a81612c45565b6000600860008581526020019081526020016000209050611c5a8161400e565b6000816000015490506000600b8281548110611c7957611c78615fa1565b5b9060005260206000209060030201905084816000015434611c9a9190616161565b14611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd19061624d565b60405180910390fd5b611d46600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550611dbc838683600101546144cc565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d86604051611dec9190615047565b60405180910390a2505050505050565b611e0d611e07613065565b836133b7565b611e4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4390615efa565b60405180910390fd5b611e58848484846145c5565b50505050565b611e66612bfb565b60008060005b85859050811015611f6757858582818110611e8a57611e89615fa1565b5b905060200201359250611e9c83612c45565b6008600084815260200190815260200160002091506000611ec08360020154612cbe565b14611f00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ef790615ce4565b60405180910390fd5b611f0983612d37565b611f138285612e85565b8373ffffffffffffffffffffffffffffffffffffffff16837fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee60405160405180910390a3611f6081613d59565b9050611e6c565b505050505050565b611f77612bfb565b60018383905011611fbd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fb4906162b9565b60405180910390fd5b60003490506000806000808787905090505b60008111156122df57611fe1816144bf565b9050878782818110611ff657611ff5615fa1565b5b90506020020135935061200884612c45565b60086000858152602001908152602001600020925061202683613126565b60008360000154905060008460030160009054906101000a900460a01b9050600b828154811061205957612058615fa1565b5b9060005260206000209060030201935083600101548810156120b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a790616325565b60405180910390fd5b8360000154876120c09190616161565b96506120cf8560010154614621565b1561218a5761212f600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008481526020019081526020016000208190555061223c565b6121e5600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055505b600083146122525761224d86612d37565b6122d8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff856001018190555061228685888a6144cc565b89896040516122969291906163ba565b60405180910390207fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12888a6040516122cf9291906163d3565b60405180910390a25b5050611fcf565b5050505050505050565b60606122f48261301a565b60006122fe61464e565b9050600081511161231e5760405180602001604052806000815250612349565b8061232884614665565b604051602001612339929190616438565b6040516020818303038152906040525b915050919050565b612359613c78565b6000820361239c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612393906164a8565b60405180910390fd5b6000600c600084815260200190815260200160002060008381526020019081526020016000205414612403576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123fa90616514565b60405180910390fd5b600b60405180606001604052808481526020018381526020014381525090806001815401808255809150506001900390600052602060002090600302016000909190919091506000820151816000015560208201518160010155604082015181600201555050600b80549050600c60008481526020019081526020016000206000838152602001908152602001600020819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b782826040516124c89291906163d3565b60405180910390a15050565b60006124de612bfb565b6000821180156124f857503482866124f69190616534565b145b612537576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252e906161e1565b60405180910390fd5b60006125438686613d66565b905061254e81613e17565b600160075401915060005b838110156125c25761256b8286613e62565b80836125779190616161565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8689896040516125aa93929190615ffd565b60405180910390a26125bb81613d59565b9050612559565b5050949350505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6125f8612bfb565b8161260281612c45565b60006008600085815260200190815260200160002090506126228161400e565b6000816000015490506000600b828154811061264157612640615fa1565b5b9060005260206000209060030201905080600101548511612697576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161268e9061624d565b60405180910390fd5b612703600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550612779838260000154876144cc565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea4866040516127a99190615047565b60405180910390a2505050505050565b60006127c3612bfb565b348251856127d19190616534565b14612811576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612808906161e1565b60405180910390fd5b600061281d8585613d66565b905061282881613e17565b600160075401915060005b83518110156128d1576128608285838151811061285357612852615fa1565b5b6020026020010151613e62565b808361286c9190616161565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8583815181106128a05761289f615fa1565b5b602002602001015188886040516128b993929190615ffd565b60405180910390a26128ca81613d59565b9050612833565b50509392505050565b6128e2613c78565b43600b6128ef8484613d66565b81548110612900576128ff615fa1565b5b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b782826040516129469291906163d3565b60405180910390a15050565b61295a612bfb565b60008060005b84849050811015612a3f5784848281811061297e5761297d615fa1565b5b90506020020135925061299083612c45565b6008600084815260200190815260200160002091506129ae82613126565b60006129b983613ae7565b146129f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f090615f81565b60405180910390fd5b612a0282613b91565b827f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b260405160405180910390a2612a3881613d59565b9050612960565b5050505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b612ae2613c78565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600b612b0f8484613d66565b81548110612b2057612b1f615fa1565b5b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051612b669291906163d3565b60405180910390a15050565b61ca8081565b612b80613c78565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612bef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be6906165e8565b60405180910390fd5b612bf88161422a565b50565b612c03611413565b15612c43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c3a90616654565b60405180910390fd5b565b612c4e816115f6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cb2906166c0565b60405180910390fd5b50565b6000612cc982614621565b612d08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cff9061672c565b60405180910390fd5b600061ca8083612d189190616161565b9050438111612d2b576000915050612d32565b4381039150505b919050565b6000612d42826115f6565b9050612d52816000846001614733565b612d5b826115f6565b90506004600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506002600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905581600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612e8181600084600161481e565b5050565b6000600b836000015481548110612e9f57612e9e615fa1565b5b906000526020600020906003020160000154905060008273ffffffffffffffffffffffffffffffffffffffff1682604051612ed99061677d565b60006040518083038185875af1925050503d8060008114612f16576040519150601f19603f3d011682016040523d82523d6000602084013e612f1b565b606091505b5050905080612f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f56906167de565b60405180910390fd5b50505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612fd881614824565b613017576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161300e90616080565b60405180910390fd5b50565b61302381614824565b613062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161305990616080565b60405180910390fd5b50565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff166130e0836115f6565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6131338160020154614621565b15613173576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161316a9061684a565b60405180910390fd5b50565b60008260000154905060008360030160009054906101000a900460a01b905061319e84613ae7565b8310156131e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131d790616325565b60405180910390fd5b6000613211600b84815481106131f9576131f8615fa1565b5b90600052602060002090600302016000015485613d66565b905061321c81613e17565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85600101819055506132a0600960008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000858152602001908152602001600020546144bf565b600960008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008581526020019081526020016000208190555080856000018190555061335a600a60008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083815260200190815260200160002054613d59565b600a60008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000838152602001908152602001600020819055505050505050565b6000806133c3836115f6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061340557506134048185612a46565b5b8061344357508373ffffffffffffffffffffffffffffffffffffffff1661342b84610d9c565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661346c826115f6565b73ffffffffffffffffffffffffffffffffffffffff16146134c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016134b9906168dc565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613531576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135289061696e565b60405180910390fd5b61353e8383836001614733565b8273ffffffffffffffffffffffffffffffffffffffff1661355e826115f6565b73ffffffffffffffffffffffffffffffffffffffff16146135b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135ab906168dc565b60405180910390fd5b6004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4613740838383600161481e565b505050565b61374e82613126565b60008260000154905060008360030160009054906101000a900460a01b90508273ffffffffffffffffffffffffffffffffffffffff19168173ffffffffffffffffffffffffffffffffffffffff1916036137dd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137d49061624d565b60405180910390fd5b6137ea8460010154614621565b156139565761384a600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055506138fb600960008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600960008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550613ab9565b6139b1600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550613a62600a60008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600a60008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055505b828460030160006101000a8154816bffffffffffffffffffffffff021916908360a01c021790555050505050565b60008082600101549050613afa81614621565b613b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613b30906169da565b60405180910390fd5b6000600b846000015481548110613b5357613b52615fa1565b5b90600052602060002090600302016001015482613b709190616161565b9050438111613b8457600092505050613b8c565b438103925050505b919050565b438160020181905550613c0a600960008360030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083600001548152602001908152602001600020546144bf565b600960008360030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000836000015481526020019081526020016000208190555050565b613c80613065565b73ffffffffffffffffffffffffffffffffffffffff16613c9e611a62565b73ffffffffffffffffffffffffffffffffffffffff1614613cf4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613ceb90616a46565b60405180910390fd5b565b613cfe614865565b6000600660146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa613d42613065565b604051613d4f9190615135565b60405180910390a1565b6000600182019050919050565b600080600c6000858152602001908152602001600020600084815260200190815260200160002054905060008111613dd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613dca90616ab2565b60405180910390fd5b613ddc816144bf565b91505092915050565b600043600b8381548110613dfc57613dfb615fa1565b5b90600052602060002090600302016002015411159050919050565b613e2081613de5565b613e5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613e5690616b1e565b60405180910390fd5b50565b613e6d600754613d59565b60078190555060405180608001604052808381526020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81526020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81526020018273ffffffffffffffffffffffffffffffffffffffff191681525060086000600754815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a8154816bffffffffffffffffffffffff021916908360a01c0217905550905050613fa8600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008481526020019081526020016000208190555061400a336007546148ae565b5050565b61401b8160010154614621565b1561405b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161405290616b8a565b60405180910390fd5b50565b60008160000154905060008260030160009054906101000a900460a01b90504383600101819055506140e1600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550614192600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550505050565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6142f8612bfb565b6001600660146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861433c613065565b6040516143499190615135565b60405180910390a1565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036143c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016143b890616bf6565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516144b29190614ff0565b60405180910390a3505050565b6000600182039050919050565b60006144d88383613d66565b90506144e381613e17565b61454f600a60008660030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083815260200190815260200160002054613d59565b600a60008660030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008381526020019081526020016000208190555080846000018190555050505050565b6145d084848461344c565b6145dc848484846148cc565b61461b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161461290616c88565b60405180910390fd5b50505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214159050919050565b606060405180602001604052806000815250905090565b60606000600161467484614a53565b01905060008167ffffffffffffffff811115614693576146926158b1565b5b6040519080825280601f01601f1916602001820160405280156146c55781602001600182028036833780820191505090505b509050600082602001820190505b600115614728578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161471c5761471b616ca8565b5b049450600085036146d3575b819350505050919050565b60018114614776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161476d90616d23565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806147cd57506147cb6008600084815260200190815260200160002060020154614621565b155b61480c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161480390616d8f565b60405180910390fd5b61481884848484614ba6565b50505050565b50505050565b60008073ffffffffffffffffffffffffffffffffffffffff16614846836141ed565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b61486d611413565b6148ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016148a390616dfb565b60405180910390fd5b565b6148c8828260405180602001604052806000815250614bac565b5050565b60006148ed8473ffffffffffffffffffffffffffffffffffffffff16614c07565b15614a46578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02614916613065565b8786866040518563ffffffff1660e01b81526004016149389493929190616e70565b6020604051808303816000875af192505050801561497457506040513d601f19601f820116820180604052508101906149719190616ed1565b60015b6149f6573d80600081146149a4576040519150601f19603f3d011682016040523d82523d6000602084013e6149a9565b606091505b5060008151036149ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016149e590616c88565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050614a4b565b600190505b949350505050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310614ab1577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381614aa757614aa6616ca8565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310614aee576d04ee2d6d415b85acef81000000008381614ae457614ae3616ca8565b5b0492506020810190505b662386f26fc100008310614b1d57662386f26fc100008381614b1357614b12616ca8565b5b0492506010810190505b6305f5e1008310614b46576305f5e1008381614b3c57614b3b616ca8565b5b0492506008810190505b6127108310614b6b576127108381614b6157614b60616ca8565b5b0492506004810190505b60648310614b8e5760648381614b8457614b83616ca8565b5b0492506002810190505b600a8310614b9d576001810190505b80915050919050565b50505050565b614bb68383614c2a565b614bc360008484846148cc565b614c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614bf990616c88565b60405180910390fd5b505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603614c99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614c9090616f4a565b60405180910390fd5b614ca281614824565b15614ce2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614cd990616fb6565b60405180910390fd5b614cf0600083836001614733565b614cf981614824565b15614d39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614d3090616fb6565b60405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4614e4360008383600161481e565b5050565b60405180606001604052806000815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b614e8f81614e7c565b8114614e9a57600080fd5b50565b600081359050614eac81614e86565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000614edd82614eb2565b9050919050565b614eed81614ed2565b8114614ef857600080fd5b50565b600081359050614f0a81614ee4565b92915050565b60008060408385031215614f2757614f26614e72565b5b6000614f3585828601614e9d565b9250506020614f4685828601614efb565b9150509250929050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b614f8581614f50565b8114614f9057600080fd5b50565b600081359050614fa281614f7c565b92915050565b600060208284031215614fbe57614fbd614e72565b5b6000614fcc84828501614f93565b91505092915050565b60008115159050919050565b614fea81614fd5565b82525050565b60006020820190506150056000830184614fe1565b92915050565b60006020828403121561502157615020614e72565b5b600061502f84828501614e9d565b91505092915050565b61504181614e7c565b82525050565b600060208201905061505c6000830184615038565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561509c578082015181840152602081019050615081565b60008484015250505050565b6000601f19601f8301169050919050565b60006150c482615062565b6150ce818561506d565b93506150de81856020860161507e565b6150e7816150a8565b840191505092915050565b6000602082019050818103600083015261510c81846150b9565b905092915050565b600061511f82614eb2565b9050919050565b61512f81615114565b82525050565b600060208201905061514a6000830184615126565b92915050565b61515981615114565b811461516457600080fd5b50565b60008135905061517681615150565b92915050565b6000806040838503121561519357615192614e72565b5b60006151a185828601615167565b92505060206151b285828601614e9d565b9150509250929050565b600080604083850312156151d3576151d2614e72565b5b60006151e185828601614e9d565b92505060206151f285828601614e9d565b9150509250929050565b60008060006060848603121561521557615214614e72565b5b600061522386828701615167565b935050602061523486828701615167565b925050604061524586828701614e9d565b9150509250925092565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b6152848161524f565b811461528f57600080fd5b50565b6000813590506152a18161527b565b92915050565b600080604083850312156152be576152bd614e72565b5b60006152cc85828601614e9d565b92505060206152dd85828601615292565b9150509250929050565b600080fd5b600080fd5b600080fd5b60008083601f84011261530c5761530b6152e7565b5b8235905067ffffffffffffffff811115615329576153286152ec565b5b602083019150836020820283011115615345576153446152f1565b5b9250929050565b6000806020838503121561536357615362614e72565b5b600083013567ffffffffffffffff81111561538157615380614e77565b5b61538d858286016152f6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6153fa81614e7c565b82525050565b600061540c83836153f1565b60208301905092915050565b6000602082019050919050565b6000615430826153c5565b61543a81856153d0565b9350615445836153e1565b8060005b8381101561547657815161545d8882615400565b975061546883615418565b925050600181019050615449565b5085935050505092915050565b600061548f8383615425565b905092915050565b6000602082019050919050565b60006154af82615399565b6154b981856153a4565b9350836020820285016154cb856153b5565b8060005b8581101561550757848403895281516154e88582615483565b94506154f383615497565b925060208a019950506001810190506154cf565b50829750879550505050505092915050565b6000602082019050818103600083015261553381846154a4565b905092915050565b6155448161524f565b82525050565b600060a08201905061555f6000830188615038565b61556c6020830187615038565b6155796040830186615038565b6155866060830185615038565b615593608083018461553b565b9695505050505050565b60008083601f8401126155b3576155b26152e7565b5b8235905067ffffffffffffffff8111156155d0576155cf6152ec565b5b6020830191508360208202830111156155ec576155eb6152f1565b5b9250929050565b60008060006040848603121561560c5761560b614e72565b5b600084013567ffffffffffffffff81111561562a57615629614e77565b5b6156368682870161559d565b9350935050602061564986828701614e9d565b9150509250925092565b6000806020838503121561566a57615669614e72565b5b600083013567ffffffffffffffff81111561568857615687614e77565b5b6156948582860161559d565b92509250509250929050565b6000602082840312156156b6576156b5614e72565b5b60006156c484828501615167565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60608201600082015161570f60008501826153f1565b50602082015161572260208501826153f1565b50604082015161573560408501826153f1565b50505050565b600061574783836156f9565b60608301905092915050565b6000602082019050919050565b600061576b826156cd565b61577581856156d8565b9350615780836156e9565b8060005b838110156157b1578151615798888261573b565b97506157a383615753565b925050600181019050615784565b5085935050505092915050565b600060208201905081810360008301526157d88184615760565b905092915050565b6157e981614fd5565b81146157f457600080fd5b50565b600081359050615806816157e0565b92915050565b6000806040838503121561582357615822614e72565b5b600061583185828601615167565b9250506020615842858286016157f7565b9150509250929050565b60008060006040848603121561586557615864614e72565b5b600084013567ffffffffffffffff81111561588357615882614e77565b5b61588f8682870161559d565b935093505060206158a286828701615292565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6158e9826150a8565b810181811067ffffffffffffffff82111715615908576159076158b1565b5b80604052505050565b600061591b614e68565b905061592782826158e0565b919050565b600067ffffffffffffffff821115615947576159466158b1565b5b615950826150a8565b9050602081019050919050565b82818337600083830152505050565b600061597f61597a8461592c565b615911565b90508281526020810184848401111561599b5761599a6158ac565b5b6159a684828561595d565b509392505050565b600082601f8301126159c3576159c26152e7565b5b81356159d384826020860161596c565b91505092915050565b600080600080608085870312156159f6576159f5614e72565b5b6000615a0487828801615167565b9450506020615a1587828801615167565b9350506040615a2687828801614e9d565b925050606085013567ffffffffffffffff811115615a4757615a46614e77565b5b615a53878288016159ae565b91505092959194509250565b600080600060408486031215615a7857615a77614e72565b5b600084013567ffffffffffffffff811115615a9657615a95614e77565b5b615aa28682870161559d565b93509350506020615ab586828701614efb565b9150509250925092565b60008060008060808587031215615ad957615ad8614e72565b5b6000615ae787828801614e9d565b9450506020615af887828801614e9d565b9350506040615b0987828801615292565b9250506060615b1a87828801614e9d565b91505092959194509250565b600067ffffffffffffffff821115615b4157615b406158b1565b5b602082029050602081019050919050565b6000615b65615b6084615b26565b615911565b90508083825260208201905060208402830185811115615b8857615b876152f1565b5b835b81811015615bb15780615b9d8882615292565b845260208401935050602081019050615b8a565b5050509392505050565b600082601f830112615bd057615bcf6152e7565b5b8135615be0848260208601615b52565b91505092915050565b600080600060608486031215615c0257615c01614e72565b5b6000615c1086828701614e9d565b9350506020615c2186828701614e9d565b925050604084013567ffffffffffffffff811115615c4257615c41614e77565b5b615c4e86828701615bbb565b9150509250925092565b60008060408385031215615c6f57615c6e614e72565b5b6000615c7d85828601615167565b9250506020615c8e85828601615167565b9150509250929050565b7f6e6f7420726561647920746f2077697468647261770000000000000000000000600082015250565b6000615cce60158361506d565b9150615cd982615c98565b602082019050919050565b60006020820190508181036000830152615cfd81615cc1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680615d4b57607f821691505b602082108103615d5e57615d5d615d04565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000615dc060218361506d565b9150615dcb82615d64565b604082019050919050565b60006020820190508181036000830152615def81615db3565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60008201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b6000615e52603d8361506d565b9150615e5d82615df6565b604082019050919050565b60006020820190508181036000830152615e8181615e45565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560008201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b6000615ee4602d8361506d565b9150615eef82615e88565b604082019050919050565b60006020820190508181036000830152615f1381615ed7565b9050919050565b6000602082019050615f2f600083018461553b565b92915050565b7f6e6f7420726561647920746f20756e7374616b65000000000000000000000000600082015250565b6000615f6b60148361506d565b9150615f7682615f35565b602082019050919050565b60006020820190508181036000830152615f9a81615f5e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215615fe657615fe5614e72565b5b6000615ff484828501615292565b91505092915050565b6000606082019050616012600083018661553b565b61601f6020830185615038565b61602c6040830184615038565b949350505050565b7f4552433732313a20696e76616c696420746f6b656e2049440000000000000000600082015250565b600061606a60188361506d565b915061607582616034565b602082019050919050565b600060208201905081810360008301526160998161605d565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f74206120766160008201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b60006160fc60298361506d565b9150616107826160a0565b604082019050919050565b6000602082019050818103600083015261612b816160ef565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061616c82614e7c565b915061617783614e7c565b925082820190508082111561618f5761618e616132565b5b92915050565b7f696e76616c696420706172616d65746572730000000000000000000000000000600082015250565b60006161cb60128361506d565b91506161d682616195565b602082019050919050565b600060208201905081810360008301526161fa816161be565b9050919050565b7f696e76616c6964206f7065726174696f6e000000000000000000000000000000600082015250565b600061623760118361506d565b915061624282616201565b602082019050919050565b600060208201905081810360008301526162668161622a565b9050919050565b7f696e76616c6964206c656e677468000000000000000000000000000000000000600082015250565b60006162a3600e8361506d565b91506162ae8261626d565b602082019050919050565b600060208201905081810360008301526162d281616296565b9050919050565b7f696e76616c6964206475726174696f6e00000000000000000000000000000000600082015250565b600061630f60108361506d565b915061631a826162d9565b602082019050919050565b6000602082019050818103600083015261633e81616302565b9050919050565b600081905092915050565b600080fd5b82818337505050565b600061636a8385616345565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561639d5761639c616350565b5b6020830292506163ae838584616355565b82840190509392505050565b60006163c782848661635e565b91508190509392505050565b60006040820190506163e86000830185615038565b6163f56020830184615038565b9392505050565b600081905092915050565b600061641282615062565b61641c81856163fc565b935061642c81856020860161507e565b80840191505092915050565b60006164448285616407565b91506164508284616407565b91508190509392505050565b7f616d6f756e7420697320696e76616c6964000000000000000000000000000000600082015250565b600061649260118361506d565b915061649d8261645c565b602082019050919050565b600060208201905081810360008301526164c181616485565b9050919050565b7f6475706c6963617465206275636b657420747970650000000000000000000000600082015250565b60006164fe60158361506d565b9150616509826164c8565b602082019050919050565b6000602082019050818103600083015261652d816164f1565b9050919050565b600061653f82614e7c565b915061654a83614e7c565b925082820261655881614e7c565b9150828204841483151761656f5761656e616132565b5b5092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006165d260268361506d565b91506165dd82616576565b604082019050919050565b60006020820190508181036000830152616601816165c5565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b600061663e60108361506d565b915061664982616608565b602082019050919050565b6000602082019050818103600083015261666d81616631565b9050919050565b7f6e6f74206f776e65720000000000000000000000000000000000000000000000600082015250565b60006166aa60098361506d565b91506166b582616674565b602082019050919050565b600060208201905081810360008301526166d98161669d565b9050919050565b7f6e6f7420616e20756e7374616b6564206275636b657400000000000000000000600082015250565b600061671660168361506d565b9150616721826166e0565b602082019050919050565b6000602082019050818103600083015261674581616709565b9050919050565b600081905092915050565b50565b600061676760008361674c565b915061677282616757565b600082019050919050565b60006167888261675a565b9150819050919050565b7f6661696c656420746f207472616e736665720000000000000000000000000000600082015250565b60006167c860128361506d565b91506167d382616792565b602082019050919050565b600060208201905081810360008301526167f7816167bb565b9050919050565b7f6e6f742061207374616b656420746f6b656e0000000000000000000000000000600082015250565b600061683460128361506d565b915061683f826167fe565b602082019050919050565b6000602082019050818103600083015261686381616827565b9050919050565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b60006168c660258361506d565b91506168d18261686a565b604082019050919050565b600060208201905081810360008301526168f5816168b9565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061695860248361506d565b9150616963826168fc565b604082019050919050565b600060208201905081810360008301526169878161694b565b9050919050565b7f6e6f7420616e20756e6c6f636b6564206275636b657400000000000000000000600082015250565b60006169c460168361506d565b91506169cf8261698e565b602082019050919050565b600060208201905081810360008301526169f3816169b7565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000616a3060208361506d565b9150616a3b826169fa565b602082019050919050565b60006020820190508181036000830152616a5f81616a23565b9050919050565b7f696e76616c6964206275636b6574207479706500000000000000000000000000600082015250565b6000616a9c60138361506d565b9150616aa782616a66565b602082019050919050565b60006020820190508181036000830152616acb81616a8f565b9050919050565b7f696e616374697665206275636b65742074797065000000000000000000000000600082015250565b6000616b0860148361506d565b9150616b1382616ad2565b602082019050919050565b60006020820190508181036000830152616b3781616afb565b9050919050565b7f6e6f742061206c6f636b656420746f6b656e0000000000000000000000000000600082015250565b6000616b7460128361506d565b9150616b7f82616b3e565b602082019050919050565b60006020820190508181036000830152616ba381616b67565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b6000616be060198361506d565b9150616beb82616baa565b602082019050919050565b60006020820190508181036000830152616c0f81616bd3565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b6000616c7260328361506d565b9150616c7d82616c16565b604082019050919050565b60006020820190508181036000830152616ca181616c65565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f6261746368207472616e73666572206973206e6f7420737570706f7274656400600082015250565b6000616d0d601f8361506d565b9150616d1882616cd7565b602082019050919050565b60006020820190508181036000830152616d3c81616d00565b9050919050565b7f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000600082015250565b6000616d79601e8361506d565b9150616d8482616d43565b602082019050919050565b60006020820190508181036000830152616da881616d6c565b9050919050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000616de560148361506d565b9150616df082616daf565b602082019050919050565b60006020820190508181036000830152616e1481616dd8565b9050919050565b600081519050919050565b600082825260208201905092915050565b6000616e4282616e1b565b616e4c8185616e26565b9350616e5c81856020860161507e565b616e65816150a8565b840191505092915050565b6000608082019050616e856000830187615126565b616e926020830186615126565b616e9f6040830185615038565b8181036060830152616eb18184616e37565b905095945050505050565b600081519050616ecb81614f7c565b92915050565b600060208284031215616ee757616ee6614e72565b5b6000616ef584828501616ebc565b91505092915050565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b6000616f3460208361506d565b9150616f3f82616efe565b602082019050919050565b60006020820190508181036000830152616f6381616f27565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b6000616fa0601c8361506d565b9150616fab82616f6a565b602082019050919050565b60006020820190508181036000830152616fcf81616f93565b905091905056fea2646970667358221220d4fb1d4a5f31b44bb4783b1e7268c7deb8646c92668ae8c0866d990b17ca737864736f6c63430008120033` +) + +func TestLiquidStaking(t *testing.T) { + require := require.New(t) + + testReadContract := func(cfg config.Config, t *testing.T) { + ctx := context.Background() + + // Create a new blockchain + svr, err := itx.NewServer(cfg) + require.NoError(err) + require.NoError(svr.Start(ctx)) + defer func() { + require.NoError(svr.Stop(ctx)) + }() + + chainID := cfg.Chain.ID + bc := svr.ChainService(chainID).Blockchain() + sf := svr.ChainService(chainID).StateFactory() + ap := svr.ChainService(chainID).ActionPool() + dao := svr.ChainService(chainID).BlockDAO() + registry := svr.ChainService(chainID).Registry() + require.NotNil(bc) + require.NotNil(registry) + admin := identityset.PrivateKey(26) + state0 := hash.BytesToHash160(identityset.Address(26).Bytes()) + s := &state.Account{} + _, err = sf.State(s, protocol.LegacyKeyOption(state0)) + require.NoError(err) + require.Equal(unit.ConvertIotxToRau(100000000), s.Balance) + + // deploy staking contract + data, err := hex.DecodeString(_liquidStakingContractByteCode) + require.NoError(err) + fixedTime := time.Unix(cfg.Genesis.Timestamp, 0) + ex, err := action.SignedExecution(action.EmptyAddress, admin, 1, big.NewInt(0), 10000000, big.NewInt(testutil.TestGasPriceInt64), data) + require.NoError(err) + + deployHash, err := ex.Hash() + require.NoError(err) + require.NoError(ap.Add(context.Background(), ex)) + blk, err := bc.MintNewBlock(fixedTime) + require.NoError(err) + require.NoError(bc.CommitBlock(blk)) + r, err := dao.GetReceiptByActionHash(deployHash, 1) + require.NoError(err) + require.Equal(r.ContractAddress, "io123vqxxup8n3ld8jygvx729r6295pv9krjn2tjh") + + // set value + // contractABI, err := abi.JSON(strings.NewReader(blockindex.LiquidStakingContractABI)) + // require.NoError(err) + fixedAmount := unit.ConvertIotxToRau(200) + // sk := identityset.PrivateKey(26) + nonce := uint64(0) + // data, err = contractABI.Pack("addBucketType", big.NewInt(10), big.NewInt(10000)) + // require.NoError(err) + // require.True(len(data) > 0) + data, err = hex.DecodeString(`c8e7792300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000002710`) + require.NoError(err) + ex, err = action.SignedExecution(r.ContractAddress, admin, nonce+2, fixedAmount, 10000000, big.NewInt(testutil.TestGasPriceInt64), data) + require.NoError(err) + require.NoError(ap.Add(context.Background(), ex)) + // data, err = contractABI.Pack("get") + // require.NoError(err) + // require.True(len(data) > 0) + // ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) + // require.NoError(err) + // require.NoError(ap.Add(context.Background(), ex)) + blk, err = bc.MintNewBlock(fixedTime) + require.NoError(err) + require.NoError(bc.CommitBlock(blk)) + } + + cfg := config.Default + testTriePath, err := testutil.PathOfTempFile("trie") + require.NoError(err) + testDBPath, err := testutil.PathOfTempFile("db") + require.NoError(err) + testIndexPath, err := testutil.PathOfTempFile("index") + require.NoError(err) + testBloomfilterIndexPath, err := testutil.PathOfTempFile("bloomfilterindex") + require.NoError(err) + testCandidateIndexPath, err := testutil.PathOfTempFile("candidateindex") + require.NoError(err) + testLiquidStakeIndexPath, err := testutil.PathOfTempFile("liquidstakeindex") + require.NoError(err) + testSystemLogPath, err := testutil.PathOfTempFile("systemlog") + require.NoError(err) + testConsensusPath, err := testutil.PathOfTempFile("consensus") + require.NoError(err) + defer func() { + testutil.CleanupPath(testTriePath) + testutil.CleanupPath(testDBPath) + testutil.CleanupPath(testIndexPath) + testutil.CleanupPath(testBloomfilterIndexPath) + testutil.CleanupPath(testCandidateIndexPath) + testutil.CleanupPath(testLiquidStakeIndexPath) + testutil.CleanupPath(testSystemLogPath) + testutil.CleanupPath(testConsensusPath) + // clear the gateway + delete(cfg.Plugins, config.GatewayPlugin) + }() + + cfg.ActPool.MinGasPriceStr = "0" + cfg.Chain.TrieDBPatchFile = "" + cfg.Chain.TrieDBPath = testTriePath + cfg.Chain.ChainDBPath = testDBPath + cfg.Chain.IndexDBPath = testIndexPath + cfg.Chain.BloomfilterIndexDBPath = testBloomfilterIndexPath + cfg.Chain.CandidateIndexDBPath = testCandidateIndexPath + cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexPath + cfg.System.SystemLogDBPath = testSystemLogPath + cfg.Consensus.RollDPoS.ConsensusDBPath = testConsensusPath + cfg.Chain.ProducerPrivKey = "a000000000000000000000000000000000000000000000000000000000000000" + cfg.Consensus.Scheme = config.RollDPoSScheme + cfg.Genesis.NumDelegates = 1 + cfg.Genesis.NumSubEpochs = 10 + cfg.Genesis.Delegates = []genesis.Delegate{ + { + OperatorAddrStr: identityset.Address(0).String(), + RewardAddrStr: identityset.Address(0).String(), + VotesStr: "10", + }, + } + cfg.Genesis.PollMode = "lifeLong" + cfg.Genesis.EnableGravityChainVoting = false + cfg.Genesis.ActionGasLimit = 100000000 + cfg.Plugins[config.GatewayPlugin] = true + cfg.Chain.EnableAsyncIndexWrite = false + cfg.Genesis.AleutianBlockHeight = 0 + cfg.Genesis.BeringBlockHeight = 0 + cfg.Genesis.HawaiiBlockHeight = 0 + + t.Run("test read staking contract", func(t *testing.T) { + testReadContract(cfg, t) + }) +} From 7e531a4c43040c234637b1bc7641aac961830e8e Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 26 Apr 2023 22:54:45 +0800 Subject: [PATCH 13/51] add test --- action/protocol/execution/protocol_test.go | 12 +- .../execution/testdata/system-staking.json | 53 + .../execution/testdata/system-staking.sol | 570 ++++ blockchain/genesis/genesis.go | 2 +- blockindex/indexpb/liquidstaking_bucket.pb.go | 64 +- blockindex/indexpb/liquidstaking_bucket.proto | 8 +- blockindex/liquidstaking_data.go | 8 +- blockindex/liquidstaking_indexer.go | 2540 +++++++++-------- e2etest/liquid_staking_test.go | 410 ++- e2etest/staking_test.go | 5 + 10 files changed, 2291 insertions(+), 1381 deletions(-) create mode 100644 action/protocol/execution/testdata/system-staking.json create mode 100644 action/protocol/execution/testdata/system-staking.sol diff --git a/action/protocol/execution/protocol_test.go b/action/protocol/execution/protocol_test.go index dc2a5a8215..e0b31cd420 100644 --- a/action/protocol/execution/protocol_test.go +++ b/action/protocol/execution/protocol_test.go @@ -381,8 +381,12 @@ func (sct *SmartContractTest) prepareBlockchain( testTriePath, err := testutil.PathOfTempFile("trie") r.NoError(err) defer testutil.CleanupPath(testTriePath) + testLiquidStakeIndexerPath, err := testutil.PathOfTempFile("liquidstakeindexer") + r.NoError(err) + defer testutil.CleanupPath(testLiquidStakeIndexerPath) cfg.Chain.TrieDBPath = testTriePath + cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexerPath cfg.ActPool.MinGasPriceStr = "0" if sct.InitGenesis.IsBering { cfg.Genesis.Blockchain.AleutianBlockHeight = 0 @@ -438,8 +442,11 @@ func (sct *SmartContractTest) prepareBlockchain( // create indexer indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.Genesis.Hash()) r.NoError(err) + cc := cfg.DB + cc.DbPath = testLiquidStakeIndexerPath + liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) // create BlockDAO - dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer}) + dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) r.NotNil(dao) bc := blockchain.NewBlockchain( cfg.Chain, @@ -959,6 +966,9 @@ func TestProtocol_Handle(t *testing.T) { t.Run("CVE-2021-39137-attack-replay", func(t *testing.T) { NewSmartContractTest(t, "testdata/CVE-2021-39137-attack-replay.json") }) + t.Run("system-staking", func(t *testing.T) { + NewSmartContractTest(t, "testdata/system-staking.json") + }) } func TestMaxTime(t *testing.T) { diff --git a/action/protocol/execution/testdata/system-staking.json b/action/protocol/execution/testdata/system-staking.json new file mode 100644 index 0000000000..20c525ee31 --- /dev/null +++ b/action/protocol/execution/testdata/system-staking.json @@ -0,0 +1,53 @@ +{ + "initGenesis": { + "isBering": true, + "isIceland": true + }, + "initBalances": [ + { + "account": "io1llupp3n8q5x8usnr5w08j6hc6hn55x64l46rr7", + "rawBalance": "1000000000000000000000000000" + } + ], + "deployments":[ + { + "rawByteCode": "60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b2366004613430565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613476565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613493565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134fc565b34801561034a57600080fd5b5061035e610359366004613493565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b761039136600461350f565b610ab4565b3480156103a257600080fd5b506102b76103b136600461353b565b610bc9565b3480156103c257600080fd5b506102b76103d136600461355d565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135bb565b610c6d565b34801561040257600080fd5b506102b7610411366004613493565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b610446366004613632565b610d9c565b6040516102e59190613673565b34801561046457600080fd5b506102b761047336600461355d565b610f18565b34801561048457600080fd5b50610498610493366004613493565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e536600461353b565b610fa9565b61030e6104f83660046135bb565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136fd565b61103a565b34801561054857600080fd5b506102b7610557366004613632565b6110e1565b34801561056857600080fd5b506102b7610577366004613493565b611177565b34801561058857600080fd5b5061035e610597366004613493565b6111d9565b3480156105a857600080fd5b5061044b6105b7366004613632565b611239565b3480156105c857600080fd5b5061030e6105d7366004613748565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c36600461353b565b611445565b6040516102e59190613765565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613493565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137be565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137f1565b6115d3565b6102b76106e936600461353b565b61166a565b3480156106fa57600080fd5b506102b761070936600461388a565b611772565b34801561071a57600080fd5b506102b761072936600461394d565b6117aa565b6102b761073c3660046136fd565b611899565b34801561074d57600080fd5b5061033161075c366004613493565b611ab3565b34801561076d57600080fd5b506102b761077c36600461353b565b611b26565b61030e61078f3660046139a3565b611ccb565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c536600461353b565b611d95565b61030e6107d83660046139e0565b611e7e565b3480156107e957600080fd5b506102b76107f836600461353b565b611f70565b34801561080957600080fd5b506102b7610818366004613632565b611fe4565b34801561082957600080fd5b506102d9610838366004613aa1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b761088136600461353b565b6120c0565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613748565b612136565b6108c46121af565b816108ce816121fc565b600083815260086020526040902060028101546108ea90612251565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122c6565b6109478184612369565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612428565b6000828152600860205260409020600201546109cf90612251565b606060008054610a0a90613acf565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613acf565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612428565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612487565b505050565b610bd16121af565b81610bdb816121fc565b6000838152600860205260409020610bf2816124f5565b610bfc818461253f565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612627565b610c625760405162461bcd60e51b815260040161092b90613b09565b610bc48383836126a5565b610c756121af565b81610c7f816121fc565b6000838152600860205260409020610c979083612816565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce36121af565b80610ced816121fc565b6000828152600860205260409020610d04816124f5565b610d0d81612919565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129f9565b610d9a612a53565b565b6060816001600160401b03811115610db657610db6613844565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613844565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b56565b6020026020010181905250600060096000878785818110610e7b57610e7b613b56565b9050602002016020810190610e909190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b56565b60200260200101518281518110610ef357610ef3613b56565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612428565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b56565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612aa8565b612b0f565b9392505050565b6000610fce6121af565b346000610fdb8286612aa8565b9050610fe681612b40565b610ff08185612b8c565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b87565b60405180910390a295945050505050565b6110426121af565b60008060005b848110156110d95785858281811061106257611062613b56565b905060200201359250611074836121fc565b6000838152600860205260409020915061108d826124f5565b611097828561253f565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e96121af565b60008060005b838110156111705784848281811061110957611109613b56565b90506020020135925061111b836121fc565b6000838152600860205260409020915061113482612c2c565b61113d82612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f6121af565b80611189816121fc565b60008281526008602052604090206111a081612c2c565b6111a981612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613844565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613844565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b56565b60200260200101819052506000600a600087878581811061131857611318613b56565b905060200201602081019061132d9190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b56565b6020026020010151828151811061139057611390613b56565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129f9565b610d9a6000612cce565b60606000821180156114625750600b5461145f8385613bbf565b11155b61147e5760405162461bcd60e51b815260040161092b90613bd2565b816001600160401b0381111561149657611496613844565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b56565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b56565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129f9565b610d9a612d20565b600061159582612428565b60008281526008602052604090206115ac816124f5565b610fbd81612919565b606060018054610a0a90613acf565b6115cf338383612d63565b5050565b6115db6121af565b6000805b83811015611170578484828181106115f9576115f9613b56565b90506020020135915061160b826121fc565b60008281526008602052604090206116239084612816565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b6116726121af565b8161167c816121fc565b600083815260086020526040902061169381612c2c565b8054600b805460009190839081106116ad576116ad613b56565b90600052602060002090600302019050848160000154346116ce9190613bbf565b146116eb5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e31565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612627565b6117985760405162461bcd60e51b815260040161092b90613b09565b6117a484848484612e81565b50505050565b6117b26121af565b60008060005b848110156110d9578585828181106117d2576117d2613b56565b9050602002013592506117e4836121fc565b6000838152600860205260409020600281015490925061180390612251565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122c6565b61185b8285612369565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a16121af565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611aa9576000190187878281811061190557611905613b56565b905060200201359350611917846121fc565b60008481526008602052604090209250611930836124f5565b82546003840154600b805460a09290921b918390811061195257611952613b56565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bbf565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122c6565b611aa2565b6000196001860155611a5185888a612e31565b8989604051611a61929190613c29565b60408051918290038220898352602083018b9052917fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12910160405180910390a25b50506118e9565b5050505050505050565b6060611abe82612428565b6000611ad560408051602081019091526000815290565b90506000815111611af55760405180602001604052806000815250610fbd565b80611aff84612eb4565b604051602001611b10929190613c52565b6040516020818303038152906040529392505050565b611b2e6129f9565b81600003611b725760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bd15760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cd56121af565b600082118015611ced575034611ceb8387613c81565b145b611d095760405162461bcd60e51b815260040161092b90613bd2565b6000611d158686612aa8565b9050611d2081612b40565b600754600101915060005b83811015611d8a57611d3d8286612b8c565b611d478184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d7a93929190613b87565b60405180910390a2600101611d2b565b50505b949350505050565b611d9d6121af565b81611da7816121fc565b6000838152600860205260409020611dbe81612c2c565b8054600b80546000919083908110611dd857611dd8613b56565b9060005260206000209060030201905080600101548511611e0b5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e4c90849087612e31565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e886121af565b34825185611e969190613c81565b14611eb35760405162461bcd60e51b815260040161092b90613bd2565b6000611ebf8585612aa8565b9050611eca81612b40565b600754600101915060005b8351811015611f6757611f0182858381518110611ef457611ef4613b56565b6020026020010151612b8c565b611f0b8184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f3e57611f3e613b56565b60200260200101518888604051611f5793929190613b87565b60405180910390a2600101611ed5565b50509392505050565b611f786129f9565b43600b611f858484612aa8565b81548110611f9557611f95613b56565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cbf929190918252602082015260400190565b611fec6121af565b60008060005b838110156111705784848281811061200c5761200c613b56565b90506020020135925061201e836121fc565b60008381526008602052604090209150612037826124f5565b61204082612919565b156120845760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61208d826129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611ff2565b6120c86129f9565b600019600b6120d78484612aa8565b815481106120e7576120e7613b56565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cbf929190918252602082015260400190565b61213e6129f9565b6001600160a01b0381166121a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b6121ac81612cce565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b612205816111d9565b6001600160a01b0316336001600160a01b0316146121ac5760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361229d5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b60006122ab61ca8084613bbf565b90504381116122bd5750600092915050565b43900392915050565b60006122d1826111d9565b90506122e1816000846001612f46565b6122ea826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061238257612382613b56565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121ac5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124bc826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61255284612919565b8310156125945760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125c4600b84815481106125ac576125ac613b56565b90600052602060002090600302016000015485612aa8565b90506125cf81612b40565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612633836111d9565b9050806001600160a01b0316846001600160a01b0316148061267a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d8d5750836001600160a01b031661269384610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126b8826111d9565b6001600160a01b0316146126de5760405162461bcd60e51b815260040161092b90613c98565b6001600160a01b0382166127405760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61274d8383836001612f46565b826001600160a01b0316612760826111d9565b6001600160a01b0316146127865760405162461bcd60e51b815260040161092b90613c98565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61281f826124f5565b8154600383015460a01b6001600160a01b0319808416908216036128555760405162461bcd60e51b815260040161092b90613bfe565b6001840154600019146128ac576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128f2565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b6001810154600090600019810361296b5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061298457612984613b56565b906000526020600020906003020160010154826129a19190613bbf565b90504381116129b4575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a5b61300f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b055760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d8d565b600043600b8381548110612b2557612b25613b56565b90600052602060002090600302016002015411159050919050565b612b4981612b0f565b6121ac5760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061305f565b6001810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d286121af565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a8b3390565b816001600160a01b0316836001600160a01b031603612dc45760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e3d8383612aa8565b9050612e4881612b40565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e8c8484846126a5565b612e9884848484613079565b6117a45760405162461bcd60e51b815260040161092b90613cdd565b60606000612ec183613177565b60010190506000816001600160401b03811115612ee057612ee0613844565b6040519080825280601f01601f191660200182016040528015612f0a576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f1457509392505050565b80600114612f965760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fbe5750600082815260086020526040902060020154600019145b61300a5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061324f565b60006001600160a01b0384163b1561316f57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130bd903390899088908890600401613d2f565b6020604051808303816000875af19250505080156130f8575060408051601f3d908101601f191682019092526130f591810190613d6c565b60015b613155573d808015613126576040519150601f19603f3d011682016040523d82523d6000602084013e61312b565b606091505b50805160000361314d5760405162461bcd60e51b815260040161092b90613cdd565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d8d565b506001611d8d565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131b65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131e2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061320057662386f26fc10000830492506010015b6305f5e1008310613218576305f5e100830492506008015b612710831061322c57612710830492506004015b6064831061323e576064830492506002015b600a83106109cf5760010192915050565b6132598383613282565b6132666000848484613079565b610bc45760405162461bcd60e51b815260040161092b90613cdd565b6001600160a01b0382166132d85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561333d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b61334b600083836001612f46565b6000818152600260205260409020546001600160a01b0316156133b05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121ac57600080fd5b6000806040838503121561344357600080fd5b8235915060208301356134558161341b565b809150509250929050565b6001600160e01b0319811681146121ac57600080fd5b60006020828403121561348857600080fd5b8135610fbd81613460565b6000602082840312156134a557600080fd5b5035919050565b60005b838110156134c75781810151838201526020016134af565b50506000910152565b600081518084526134e88160208601602086016134ac565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134d0565b6000806040838503121561352257600080fd5b823561352d8161341b565b946020939093013593505050565b6000806040838503121561354e57600080fd5b50508035926020909101359150565b60008060006060848603121561357257600080fd5b833561357d8161341b565b9250602084013561358d8161341b565b929592945050506040919091013590565b80356001600160a01b0319811681146135b657600080fd5b919050565b600080604083850312156135ce57600080fd5b823591506135de6020840161359e565b90509250929050565b60008083601f8401126135f957600080fd5b5081356001600160401b0381111561361057600080fd5b6020830191508360208260051b850101111561362b57600080fd5b9250929050565b6000806020838503121561364557600080fd5b82356001600160401b0381111561365b57600080fd5b613667858286016135e7565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136ef57888603603f19018552825180518088529088019088880190845b818110156136d95783518352928a0192918a01916001016136bd565b509097505050938601939186019160010161369b565b509398975050505050505050565b60008060006040848603121561371257600080fd5b83356001600160401b0381111561372857600080fd5b613734868287016135e7565b909790965060209590950135949350505050565b60006020828403121561375a57600080fd5b8135610fbd8161341b565b602080825282518282018190526000919060409081850190868401855b828110156137b15781518051855286810151878601528501518585015260609093019290850190600101613782565b5091979650505050505050565b600080604083850312156137d157600080fd5b82356137dc8161341b565b91506020830135801515811461345557600080fd5b60008060006040848603121561380657600080fd5b83356001600160401b0381111561381c57600080fd5b613828868287016135e7565b909450925061383b90506020850161359e565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561388257613882613844565b604052919050565b600080600080608085870312156138a057600080fd5b84356138ab8161341b565b93506020858101356138bc8161341b565b93506040860135925060608601356001600160401b03808211156138df57600080fd5b818801915088601f8301126138f357600080fd5b81358181111561390557613905613844565b613917601f8201601f1916850161385a565b9150808252898482850101111561392d57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561396257600080fd5b83356001600160401b0381111561397857600080fd5b613984868287016135e7565b90945092505060208401356139988161341b565b809150509250925092565b600080600080608085870312156139b957600080fd5b84359350602085013592506139d06040860161359e565b9396929550929360600135925050565b6000806000606084860312156139f557600080fd5b83359250602080850135925060408501356001600160401b0380821115613a1b57600080fd5b818701915087601f830112613a2f57600080fd5b813581811115613a4157613a41613844565b8060051b9150613a5284830161385a565b818152918301840191848101908a841115613a6c57600080fd5b938501935b83851015613a9157613a828561359e565b82529385019390850190613a71565b8096505050505050509250925092565b60008060408385031215613ab457600080fd5b8235613abf8161341b565b915060208301356134558161341b565b600181811c90821680613ae357607f821691505b602082108103613b0357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b7e57600080fd5b610fbd8261359e565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613ba9565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b60006001600160fb1b03831115613c3f57600080fd5b8260051b80858437919091019392505050565b60008351613c648184602088016134ac565b835190830190613c788183602088016134ac565b01949350505050565b80820281158282048414176109cf576109cf613ba9565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d62908301846134d0565b9695505050505050565b600060208284031215613d7e57600080fd5b8151610fbd8161346056fea2646970667358221220f2bdba1caf01add5d9d0c859f09b34e6be24ec98d778f8a9cf110ac34053fb0664736f6c63430008130033", + "rawPrivateKey": "f964b7ccc40ccace513d3159fa9c30514c4a186ebfdd7c63d69cd79a29b804b0", + "rawAmount": "0", + "rawGasLimit": 20000000, + "rawGasPrice": "0", + "rawExpectedGasConsumed": 4885329, + "expectedStatus": 1, + "expectedBalances": [], + "comment": "deploy iip13 system staking contract" + } + ], + "executions": [ + { + "rawPrivateKey": "f964b7ccc40ccace513d3159fa9c30514c4a186ebfdd7c63d69cd79a29b804b0", + "rawByteCode": "c8e77923000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000064", + "rawAmount": "0", + "rawGasLimit": 1000000, + "rawGasPrice": "0", + "rawAccessList": [], + "rawExpectedGasConsumed": 122220, + "expectedStatus": 1, + "expectedLogs": [{}], + "rawReturnValue": "", + "comment": "add bucket type" + }, + { + "rawPrivateKey": "f964b7ccc40ccace513d3159fa9c30514c4a186ebfdd7c63d69cd79a29b804b0", + "rawByteCode": "597cc14a00000000000000000000000000000000000000000000000000000000000000640000000000000000792020100000000000000000000000000000000000000000", + "rawAmount": "10", + "rawGasLimit": 1000000, + "rawGasPrice": "0", + "rawAccessList": [], + "rawExpectedGasConsumed": 122220, + "expectedStatus": 1, + "expectedLogs": [{}], + "rawReturnValue": "", + "comment": "stake" + } + ] +} \ No newline at end of file diff --git a/action/protocol/execution/testdata/system-staking.sol b/action/protocol/execution/testdata/system-staking.sol new file mode 100644 index 0000000000..e5f4451e74 --- /dev/null +++ b/action/protocol/execution/testdata/system-staking.sol @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/security/Pausable.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +struct BucketInfo { + uint256 typeIndex; + uint256 unlockedAt; // UINT256_MAX: in lock + uint256 unstakedAt; // UINT256_MAX: in stake + bytes12 delegate; +} + +struct BucketType { + uint256 amount; + uint256 duration; + uint256 activatedAt; +} + +contract SystemStaking is ERC721, Ownable, Pausable { + uint256 public constant UINT256_MAX = type(uint256).max; + uint256 public constant UNSTAKE_FREEZE_BLOCKS = 51840; // (3 * 24 * 60 * 60) / 5; + + event BucketTypeActivated(uint256 amount, uint256 duration); + event BucketTypeDeactivated(uint256 amount, uint256 duration); + event Staked(uint256 indexed tokenId, bytes12 delegate, uint256 amount, uint256 duration); + event Locked(uint256 indexed tokenId, uint256 duration); + event Unlocked(uint256 indexed tokenId); + event Unstaked(uint256 indexed tokenId); + event Merged(uint256[] indexed tokenIds, uint256 amount, uint256 duration); + event DurationExtended(uint256 indexed tokenId, uint256 duration); + event AmountIncreased(uint256 indexed tokenId, uint256 amount); + event DelegateChanged(uint256 indexed tokenId, bytes12 newDelegate); + event Withdrawal(uint256 indexed tokenId, address indexed recipient); + + modifier onlyTokenOwner(uint256 _tokenId) { + _assertOnlyTokenOwner(_tokenId); + _; + } + + // token id + uint256 private __currTokenId; + // mapping from token ID to bucket + mapping(uint256 => BucketInfo) private __buckets; + // delegate name -> bucket type -> count + mapping(bytes12 => mapping(uint256 => uint256)) private __unlockedVotes; + // delegate name -> bucket type -> count + mapping(bytes12 => mapping(uint256 => uint256)) private __lockedVotes; + // bucket type + BucketType[] private __bucketTypes; + // amount -> duration -> index + mapping(uint256 => mapping(uint256 => uint256)) private __bucketTypeIndices; + + constructor() ERC721("BucketNFT", "BKT") {} + + function pause() external onlyOwner { + _pause(); + } + + function unpause() external onlyOwner { + _unpause(); + } + + function unsafeInc(uint256 x) private pure returns (uint256) { + unchecked { + return x + 1; + } + } + + function unsafeDec(uint256 x) private pure returns (uint256) { + unchecked { + return x - 1; + } + } + + // bucket type related functions + function addBucketType(uint256 _amount, uint256 _duration) external onlyOwner { + require(_amount != 0, "amount is invalid"); + require(__bucketTypeIndices[_amount][_duration] == 0, "duplicate bucket type"); + __bucketTypes.push(BucketType(_amount, _duration, block.number)); + __bucketTypeIndices[_amount][_duration] = __bucketTypes.length; + emit BucketTypeActivated(_amount, _duration); + } + + function deactivateBucketType(uint256 _amount, uint256 _duration) external onlyOwner { + __bucketTypes[_bucketTypeIndex(_amount, _duration)].activatedAt = UINT256_MAX; + emit BucketTypeDeactivated(_amount, _duration); + } + + function activateBucketType(uint256 _amount, uint256 _duration) external onlyOwner { + __bucketTypes[_bucketTypeIndex(_amount, _duration)].activatedAt = block.number; + emit BucketTypeActivated(_amount, _duration); + } + + function isActiveBucketType(uint256 _amount, uint256 _duration) external view returns (bool) { + return _isActiveBucketType(_bucketTypeIndex(_amount, _duration)); + } + + function numOfBucketTypes() public view returns (uint256) { + return __bucketTypes.length; + } + + function bucketTypes( + uint256 _offset, + uint256 _size + ) external view returns (BucketType[] memory types_) { + require(_size > 0 && _offset + _size <= numOfBucketTypes(), "invalid parameters"); + types_ = new BucketType[](_size); + for (uint256 i = 0; i < _size; i = unsafeInc(i)) { + unchecked { + types_[i] = __bucketTypes[_offset + i]; + } + } + } + + // token related functions + function blocksToUnstake(uint256 _tokenId) external view returns (uint256) { + _assertOnlyValidToken(_tokenId); + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyStakedToken(bucket); + return _blocksToUnstake(bucket); + } + + function blocksToWithdraw(uint256 _tokenId) external view returns (uint256) { + _assertOnlyValidToken(_tokenId); + return _blocksToWithdraw(__buckets[_tokenId].unstakedAt); + } + + function bucketOf( + uint256 _tokenId + ) + external + view + returns ( + uint256 amount_, + uint256 duration_, + uint256 unlockedAt_, + uint256 unstakedAt_, + bytes12 delegate_ + ) + { + _assertOnlyValidToken(_tokenId); + BucketInfo storage bucket = __buckets[_tokenId]; + BucketType storage bucketType = __bucketTypes[bucket.typeIndex]; + + return ( + bucketType.amount, + bucketType.duration, + bucket.unlockedAt, + bucket.unstakedAt, + bucket.delegate + ); + } + + function stake( + uint256 _duration, + bytes12 _delegate + ) external payable whenNotPaused returns (uint256) { + uint256 msgValue = msg.value; + uint256 index = _bucketTypeIndex(msgValue, _duration); + _assertOnlyActiveBucketType(index); + + _stake(index, _delegate); + uint256 tokenId = __currTokenId; + emit Staked(tokenId, _delegate, msgValue, _duration); + + return tokenId; + } + + function stake( + uint256 _amount, + uint256 _duration, + bytes12[] memory _delegates + ) external payable whenNotPaused returns (uint256 firstTokenId_) { + require(_amount * _delegates.length == msg.value, "invalid parameters"); + uint256 index = _bucketTypeIndex(_amount, _duration); + _assertOnlyActiveBucketType(index); + unchecked { + firstTokenId_ = __currTokenId + 1; + } + for (uint256 i = 0; i < _delegates.length; i = unsafeInc(i)) { + _stake(index, _delegates[i]); + emit Staked(firstTokenId_ + i, _delegates[i], _amount, _duration); + } + + return firstTokenId_; + } + + function stake( + uint256 _amount, + uint256 _duration, + bytes12 _delegate, + uint256 _count + ) external payable whenNotPaused returns (uint256 firstTokenId_) { + require(_count > 0 && _amount * _count == msg.value, "invalid parameters"); + uint256 index = _bucketTypeIndex(_amount, _duration); + _assertOnlyActiveBucketType(index); + unchecked { + firstTokenId_ = __currTokenId + 1; + } + for (uint256 i = 0; i < _count; i = unsafeInc(i)) { + _stake(index, _delegate); + emit Staked(firstTokenId_ + i, _delegate, _amount, _duration); + } + + return firstTokenId_; + } + + function unlock(uint256 _tokenId) external whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyLockedToken(bucket); + _unlock(bucket); + emit Unlocked(_tokenId); + } + + function unlock(uint256[] calldata _tokenIds) external whenNotPaused { + uint256 tokenId; + BucketInfo storage bucket; + for (uint256 i = 0; i < _tokenIds.length; i = unsafeInc(i)) { + tokenId = _tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + bucket = __buckets[tokenId]; + _assertOnlyLockedToken(bucket); + _unlock(bucket); + emit Unlocked(tokenId); + } + } + + function lock( + uint256 _tokenId, + uint256 _duration + ) external whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyStakedToken(bucket); + _lock(bucket, _duration); + emit Locked(_tokenId, _duration); + } + + function lock(uint256[] calldata _tokenIds, uint256 _duration) external whenNotPaused { + uint256 tokenId; + BucketInfo storage bucket; + for (uint256 i = 0; i < _tokenIds.length; i = unsafeInc(i)) { + tokenId = _tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + bucket = __buckets[tokenId]; + _assertOnlyStakedToken(bucket); + _lock(bucket, _duration); + emit Locked(tokenId, _duration); + } + } + + function unstake(uint256 _tokenId) external whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyStakedToken(bucket); + require(_blocksToUnstake(bucket) == 0, "not ready to unstake"); + _unstake(bucket); + emit Unstaked(_tokenId); + } + + function unstake(uint256[] calldata _tokenIds) external whenNotPaused { + uint256 tokenId; + BucketInfo storage bucket; + for (uint256 i = 0; i < _tokenIds.length; i = unsafeInc(i)) { + tokenId = _tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + bucket = __buckets[tokenId]; + _assertOnlyStakedToken(bucket); + require(_blocksToUnstake(bucket) == 0, "not ready to unstake"); + _unstake(bucket); + emit Unstaked(tokenId); + } + } + + function withdraw( + uint256 _tokenId, + address payable _recipient + ) external whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + require(_blocksToWithdraw(bucket.unstakedAt) == 0, "not ready to withdraw"); + _burn(_tokenId); + _withdraw(bucket, _recipient); + emit Withdrawal(_tokenId, _recipient); + } + + function withdraw( + uint256[] calldata _tokenIds, + address payable _recipient + ) external whenNotPaused { + uint256 tokenId; + BucketInfo storage bucket; + for (uint256 i = 0; i < _tokenIds.length; i = unsafeInc(i)) { + tokenId = _tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + bucket = __buckets[tokenId]; + require(_blocksToWithdraw(bucket.unstakedAt) == 0, "not ready to withdraw"); + _burn(tokenId); + _withdraw(bucket, _recipient); + emit Withdrawal(tokenId, _recipient); + } + } + + function merge( + uint256[] calldata tokenIds, + uint256 _newDuration + ) external payable whenNotPaused { + require(tokenIds.length > 1, "invalid length"); + uint256 amount = msg.value; + uint256 tokenId; + BucketInfo storage bucket; + BucketType storage bucketType; + for (uint256 i = tokenIds.length; i > 0; ) { + i = unsafeDec(i); + tokenId = tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + bucket = __buckets[tokenId]; + _assertOnlyStakedToken(bucket); + uint256 typeIndex = bucket.typeIndex; + bytes12 delegate = bucket.delegate; + bucketType = __bucketTypes[typeIndex]; + require(_newDuration >= bucketType.duration, "invalid duration"); + amount += bucketType.amount; + if (_isTriggered(bucket.unlockedAt)) { + __unlockedVotes[delegate][typeIndex] = unsafeDec( + __unlockedVotes[delegate][typeIndex] + ); + } else { + __lockedVotes[delegate][typeIndex] = unsafeDec(__lockedVotes[delegate][typeIndex]); + } + if (i != 0) { + _burn(tokenId); + } else { + bucket.unlockedAt = UINT256_MAX; + _updateBucketInfo(bucket, amount, _newDuration); + emit Merged(tokenIds, amount, _newDuration); + } + } + } + + function extendDuration( + uint256 _tokenId, + uint256 _newDuration + ) external whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyLockedToken(bucket); + uint256 typeIndex = bucket.typeIndex; + BucketType storage bucketType = __bucketTypes[typeIndex]; + require(_newDuration > bucketType.duration, "invalid operation"); + __lockedVotes[bucket.delegate][typeIndex] = unsafeDec( + __lockedVotes[bucket.delegate][typeIndex] + ); + _updateBucketInfo(bucket, bucketType.amount, _newDuration); + emit DurationExtended(_tokenId, _newDuration); + } + + function increaseAmount( + uint256 _tokenId, + uint256 _newAmount + ) external payable whenNotPaused onlyTokenOwner(_tokenId) { + BucketInfo storage bucket = __buckets[_tokenId]; + _assertOnlyLockedToken(bucket); + uint256 typeIndex = bucket.typeIndex; + BucketType storage bucketType = __bucketTypes[typeIndex]; + require(msg.value + bucketType.amount == _newAmount, "invalid operation"); + __lockedVotes[bucket.delegate][typeIndex] = unsafeDec( + __lockedVotes[bucket.delegate][typeIndex] + ); + _updateBucketInfo(bucket, _newAmount, bucketType.duration); + emit AmountIncreased(_tokenId, _newAmount); + } + + function changeDelegate( + uint256 _tokenId, + bytes12 _delegate + ) external whenNotPaused onlyTokenOwner(_tokenId) { + _changeDelegate(__buckets[_tokenId], _delegate); + emit DelegateChanged(_tokenId, _delegate); + } + + function changeDelegates( + uint256[] calldata _tokenIds, + bytes12 _delegate + ) external whenNotPaused { + uint256 tokenId; + for (uint256 i = 0; i < _tokenIds.length; i = unsafeInc(i)) { + tokenId = _tokenIds[i]; + _assertOnlyTokenOwner(tokenId); + _changeDelegate(__buckets[tokenId], _delegate); + emit DelegateChanged(tokenId, _delegate); + } + } + + function lockedVotesTo( + bytes12[] calldata _delegates + ) external view returns (uint256[][] memory counts_) { + counts_ = new uint256[][](_delegates.length); + uint256 tl = numOfBucketTypes(); + for (uint256 i = 0; i < _delegates.length; i = unsafeInc(i)) { + counts_[i] = new uint256[](tl); + mapping(uint256 => uint256) storage votes = __lockedVotes[_delegates[i]]; + for (uint256 j = 0; j < tl; j = unsafeInc(j)) { + counts_[i][j] = votes[j]; + } + } + + return counts_; + } + + function unlockedVotesTo( + bytes12[] calldata _delegates + ) external view returns (uint256[][] memory counts_) { + counts_ = new uint256[][](_delegates.length); + uint256 tl = numOfBucketTypes(); + for (uint256 i = 0; i < _delegates.length; i = unsafeInc(i)) { + counts_[i] = new uint256[](tl); + mapping(uint256 => uint256) storage votes = __unlockedVotes[_delegates[i]]; + for (uint256 j = 0; j < tl; j = unsafeInc(j)) { + counts_[i][j] = votes[j]; + } + } + + return counts_; + } + + ///////////////////////////////////////////// + // Private Functions + function _bucketTypeIndex(uint256 _amount, uint256 _duration) internal view returns (uint256) { + uint256 index = __bucketTypeIndices[_amount][_duration]; + require(index > 0, "invalid bucket type"); + + return unsafeDec(index); + } + + // bucket type index `_index` must be valid + function _isActiveBucketType(uint256 _index) internal view returns (bool) { + return __bucketTypes[_index].activatedAt <= block.number; + } + + function _isTriggered(uint256 _value) internal pure returns (bool) { + return _value != UINT256_MAX; + } + + function _assertOnlyTokenOwner(uint256 _tokenId) internal view { + require(msg.sender == ownerOf(_tokenId), "not owner"); + } + + function _assertOnlyLockedToken(BucketInfo storage _bucket) internal view { + require(!_isTriggered(_bucket.unlockedAt), "not a locked token"); + } + + function _assertOnlyStakedToken(BucketInfo storage _bucket) internal view { + require(!_isTriggered(_bucket.unstakedAt), "not a staked token"); + } + + function _assertOnlyValidToken(uint256 _tokenId) internal view { + require(_exists(_tokenId), "ERC721: invalid token ID"); + } + + function _assertOnlyActiveBucketType(uint256 _index) internal view { + require(_isActiveBucketType(_index), "inactive bucket type"); + } + + function _beforeTokenTransfer( + address _from, + address _to, + uint256 _firstTokenId, + uint256 _batchSize + ) internal override { + require(_batchSize == 1, "batch transfer is not supported"); + require( + _to == address(0) || !_isTriggered(__buckets[_firstTokenId].unstakedAt), + "cannot transfer unstaked token" + ); + super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize); + } + + function _blocksToWithdraw(uint256 _unstakedAt) internal view returns (uint256) { + require(_isTriggered(_unstakedAt), "not an unstaked bucket"); + uint256 withdrawBlock = _unstakedAt + UNSTAKE_FREEZE_BLOCKS; + if (withdrawBlock <= block.number) { + return 0; + } + + unchecked { + return withdrawBlock - block.number; + } + } + + function _blocksToUnstake(BucketInfo storage _bucket) internal view returns (uint256) { + uint256 unlockedAt = _bucket.unlockedAt; + require(_isTriggered(unlockedAt), "not an unlocked bucket"); + uint256 unstakeBlock = unlockedAt + __bucketTypes[_bucket.typeIndex].duration; + if (unstakeBlock <= block.number) { + return 0; + } + unchecked { + return unstakeBlock - block.number; + } + } + + function _stake(uint256 _index, bytes12 _delegate) internal { + __currTokenId = unsafeInc(__currTokenId); + __buckets[__currTokenId] = BucketInfo(_index, UINT256_MAX, UINT256_MAX, _delegate); + __lockedVotes[_delegate][_index] = unsafeInc(__lockedVotes[_delegate][_index]); + _safeMint(msg.sender, __currTokenId); + } + + function _unlock(BucketInfo storage _bucket) internal { + uint256 typeIndex = _bucket.typeIndex; + bytes12 delegate = _bucket.delegate; + _bucket.unlockedAt = block.number; + __lockedVotes[delegate][typeIndex] = unsafeDec(__lockedVotes[delegate][typeIndex]); + __unlockedVotes[delegate][typeIndex] = unsafeInc(__unlockedVotes[delegate][typeIndex]); + } + + function _lock(BucketInfo storage _bucket, uint256 _duration) internal { + uint256 typeIndex = _bucket.typeIndex; + bytes12 delegate = _bucket.delegate; + require(_duration >= _blocksToUnstake(_bucket), "invalid duration"); + uint256 newIndex = _bucketTypeIndex(__bucketTypes[typeIndex].amount, _duration); + _assertOnlyActiveBucketType(newIndex); + _bucket.unlockedAt = UINT256_MAX; + __unlockedVotes[delegate][typeIndex] = unsafeDec(__unlockedVotes[delegate][typeIndex]); + _bucket.typeIndex = newIndex; + __lockedVotes[delegate][newIndex] = unsafeInc(__lockedVotes[delegate][newIndex]); + } + + function _unstake(BucketInfo storage _bucket) internal { + _bucket.unstakedAt = block.number; + __unlockedVotes[_bucket.delegate][_bucket.typeIndex] = unsafeDec( + __unlockedVotes[_bucket.delegate][_bucket.typeIndex] + ); + } + + function _withdraw(BucketInfo storage _bucket, address payable _recipient) internal { + uint256 amount = __bucketTypes[_bucket.typeIndex].amount; + (bool success, ) = _recipient.call{value: amount}(""); + require(success, "failed to transfer"); + } + + function _updateBucketInfo( + BucketInfo storage _bucket, + uint256 _amount, + uint256 _duration + ) internal { + uint256 index = _bucketTypeIndex(_amount, _duration); + _assertOnlyActiveBucketType(index); + __lockedVotes[_bucket.delegate][index] = unsafeInc(__lockedVotes[_bucket.delegate][index]); + _bucket.typeIndex = index; + } + + function _changeDelegate(BucketInfo storage _bucket, bytes12 _newDelegate) internal { + _assertOnlyStakedToken(_bucket); + uint256 typeIndex = _bucket.typeIndex; + bytes12 delegate = _bucket.delegate; + require(delegate != _newDelegate, "invalid operation"); + if (_isTriggered(_bucket.unlockedAt)) { + __unlockedVotes[delegate][typeIndex] = unsafeDec(__unlockedVotes[delegate][typeIndex]); + __unlockedVotes[_newDelegate][typeIndex] = unsafeInc( + __unlockedVotes[_newDelegate][typeIndex] + ); + } else { + __lockedVotes[delegate][typeIndex] = unsafeDec(__lockedVotes[delegate][typeIndex]); + __lockedVotes[_newDelegate][typeIndex] = unsafeInc( + __lockedVotes[_newDelegate][typeIndex] + ); + } + _bucket.delegate = _newDelegate; + } +} \ No newline at end of file diff --git a/blockchain/genesis/genesis.go b/blockchain/genesis/genesis.go index 98a23d5d66..760bc62ef6 100644 --- a/blockchain/genesis/genesis.go +++ b/blockchain/genesis/genesis.go @@ -44,7 +44,7 @@ func defaultConfig() Genesis { Blockchain: Blockchain{ Timestamp: 1546329600, BlockGasLimit: 20000000, - ActionGasLimit: 50000000, + ActionGasLimit: 5000000, BlockInterval: 10 * time.Second, NumSubEpochs: 2, DardanellesNumSubEpochs: 30, diff --git a/blockindex/indexpb/liquidstaking_bucket.pb.go b/blockindex/indexpb/liquidstaking_bucket.pb.go index 690d64f079..f029e70767 100644 --- a/blockindex/indexpb/liquidstaking_bucket.pb.go +++ b/blockindex/indexpb/liquidstaking_bucket.pb.go @@ -98,9 +98,11 @@ type BucketInfo struct { unknownFields protoimpl.UnknownFields TypeIndex uint64 `protobuf:"varint,1,opt,name=typeIndex,proto3" json:"typeIndex,omitempty"` - UnlockedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` - UnstakedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` - Delegate string `protobuf:"bytes,4,opt,name=delegate,proto3" json:"delegate,omitempty"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=createdAt,proto3" json:"createdAt,omitempty"` + UnlockedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` + UnstakedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` + Delegate string `protobuf:"bytes,5,opt,name=delegate,proto3" json:"delegate,omitempty"` + Owner string `protobuf:"bytes,6,opt,name=owner,proto3" json:"owner,omitempty"` } func (x *BucketInfo) Reset() { @@ -142,6 +144,13 @@ func (x *BucketInfo) GetTypeIndex() uint64 { return 0 } +func (x *BucketInfo) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + func (x *BucketInfo) GetUnlockedAt() *timestamppb.Timestamp { if x != nil { return x.UnlockedAt @@ -163,6 +172,13 @@ func (x *BucketInfo) GetDelegate() string { return "" } +func (x *BucketInfo) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + var File_blockindex_indexpb_liquidstaking_bucket_proto protoreflect.FileDescriptor var file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = []byte{ @@ -179,19 +195,24 @@ var file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = []byte{ 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xbe, 0x01, 0x0a, 0x0a, 0x42, 0x75, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x8e, 0x02, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x79, 0x70, - 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x38, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3a, 0x0a, 0x0a, + 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, + 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, @@ -218,13 +239,14 @@ var file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = []interface{}{ } var file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = []int32{ 2, // 0: indexpb.BucketType.activatedAt:type_name -> google.protobuf.Timestamp - 2, // 1: indexpb.BucketInfo.unlockedAt:type_name -> google.protobuf.Timestamp - 2, // 2: indexpb.BucketInfo.unstakedAt:type_name -> google.protobuf.Timestamp - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 2, // 1: indexpb.BucketInfo.createdAt:type_name -> google.protobuf.Timestamp + 2, // 2: indexpb.BucketInfo.unlockedAt:type_name -> google.protobuf.Timestamp + 2, // 3: indexpb.BucketInfo.unstakedAt:type_name -> google.protobuf.Timestamp + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_blockindex_indexpb_liquidstaking_bucket_proto_init() } diff --git a/blockindex/indexpb/liquidstaking_bucket.proto b/blockindex/indexpb/liquidstaking_bucket.proto index c62475b9f3..10afd0ec14 100644 --- a/blockindex/indexpb/liquidstaking_bucket.proto +++ b/blockindex/indexpb/liquidstaking_bucket.proto @@ -18,7 +18,9 @@ message BucketType { message BucketInfo { uint64 typeIndex = 1; - google.protobuf.Timestamp unlockedAt = 2; - google.protobuf.Timestamp unstakedAt = 3; - string delegate = 4; + google.protobuf.Timestamp createdAt = 2; + google.protobuf.Timestamp unlockedAt = 3; + google.protobuf.Timestamp unstakedAt = 4; + string delegate = 5; + string owner = 6; } \ No newline at end of file diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index 52b5bd2c9e..970d6c9905 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -77,8 +77,14 @@ func (s *liquidStakingCache) getHeight() uint64 { } func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { + amount := bt.Amount.Int64() s.idBucketTypeMap[id] = bt - s.propertyBucketTypeMap[bt.Amount.Int64()][int64(bt.Duration)] = id + m, ok := s.propertyBucketTypeMap[amount] + if !ok { + s.propertyBucketTypeMap[amount] = make(map[int64]uint64) + m = s.propertyBucketTypeMap[amount] + } + m[int64(bt.Duration)] = id } func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index d237362fa5..a4b043cef6 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -17,7 +17,6 @@ import ( "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-core/action" - "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/blockindex/indexpb" @@ -32,1233 +31,1239 @@ import ( const ( // TODO (iip-13): replace with the real liquid staking contract address - LiquidStakingContractAddress = "" + LiquidStakingContractAddress = "io1dkqh5mu9djfas3xyrmzdv9frsmmytel4mp7a64" // LiquidStakingContractABI is the ABI of liquid staking contract LiquidStakingContractABI = `[ { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "AmountIncreased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "BucketTypeActivated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "BucketTypeDeactivated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes12", - "name": "oldDelegate", - "type": "bytes12" - }, - { - "indexed": true, - "internalType": "bytes12", - "name": "newDelegate", - "type": "bytes12" - } - ], - "name": "DelegateChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "DurationExtended", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "FeeWithdrawal", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "Locked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "bytes12", - "name": "delegate", - "type": "bytes12" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "duration", - "type": "uint256" - } - ], - "name": "Staked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Unlocked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Unstaked", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "penaltyFee", - "type": "uint256" - } - ], - "name": "Withdrawal", - "type": "event" - }, - { - "inputs": [], - "name": "UINT256_MAX", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "accumulatedWithdrawFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "activateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "addBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "activateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "blocksToUnstake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "addBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "blocksToWithdraw", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "bucketOf", - "outputs": [ - { - "internalType": "uint256", - "name": "amount_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "duration_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unlockedAt_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unstakedAt_", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "delegate_", - "type": "bytes12" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_size", - "type": "uint256" - } - ], - "name": "bucketTypes", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" }, { - "internalType": "uint256", - "name": "duration", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" }, { - "internalType": "uint256", - "name": "activatedAt", - "type": "uint256" + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" } - ], - "internalType": "struct BucketType[]", - "name": "types_", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegates", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "deactivateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "emergencyWithdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "emergencyWithdrawPenaltyRate", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newDuration", - "type": "uint256" - } - ], - "name": "extendDuration", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newAmount", - "type": "uint256" - } - ], - "name": "increaseAmount", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "isActiveBucketType", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "lock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "lockedVotesTo", - "outputs": [ - { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "numOfBucketTypes", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" + ], + "name": "Approval", + "type": "event" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" }, { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_rate", - "type": "uint256" - } - ], - "name": "setEmergencyWithdrawPenaltyRate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256[]", - "name": "tokenIds_", - "type": "uint256[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256[]", - "name": "tokenIds_", - "type": "uint256[]" - } - ], - "stateMutability": "payable", - "type": "function" + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeActivated", + "type": "event" }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeDeactivated", + "type": "event" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "unlockedVotesTo", - "outputs": [ - { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" - } - ], - "stateMutability": "view", - "type": "function" + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegates", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "withdrawFee", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "deactivateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes12", + "name": "newDelegate", + "type": "bytes12" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "DurationExtended", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" + } + ], + "name": "extendDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newAmount", + "type": "uint256" + } + ], + "name": "increaseAmount", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Locked", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" + } + ], + "name": "merge", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Merged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes12", + "name": "delegate", + "type": "bytes12" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unlocked", + "type": "event" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unstaked", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToUnstake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "bucketOf", + "outputs": [ + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unlockedAt_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unstakedAt_", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "delegate_", + "type": "bytes12" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + } + ], + "name": "bucketTypes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activatedAt", + "type": "uint256" + } + ], + "internalType": "struct BucketType[]", + "name": "types_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "isActiveBucketType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "lockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfBucketTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UINT256_MAX", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "unlockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNSTAKE_FREEZE_BLOCKS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" } - ]` + ]` // bucket related namespace in db _liquidStakingBucketInfoNS = "lsbInfo" @@ -1272,7 +1277,7 @@ type ( blockdao.BlockIndexer GetCandidateVotes(candidate string) *big.Int - GetBuckets() ([]*staking.VoteBucket, error) + GetBuckets() ([]*Bucket, error) } liquidStakingIndexer struct { @@ -1281,6 +1286,7 @@ type ( dirtyCache *liquidStakingCache clean db.KVStore // clean data in db cleanCache *liquidStakingCache // in-memory index for clean data + tokenOwner map[uint64]string // token id -> owner } // BucketInfo is the bucket information @@ -1299,6 +1305,18 @@ type ( Duration time.Duration ActivatedAt *time.Time } + // Bucket is the bucket information + Bucket struct { + Index uint64 + Candidate string + Owner address.Address + StakedAmount *big.Int + StakedDuration time.Duration + CreateTime time.Time + StakeStartTime time.Time + UnstakeStartTime time.Time + AutoStake bool + } // eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type // TODO: this is general enough to be moved to a common package @@ -1330,6 +1348,7 @@ func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) Li dirtyCache: newLiquidStakingCache(), clean: kvStore, cleanCache: newLiquidStakingCache(), + tokenOwner: make(map[uint64]string), } } @@ -1357,6 +1376,7 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e actionMap[h] = &act } + s.dirtyCache.putHeight(blk.Height()) for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue @@ -1389,8 +1409,8 @@ func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { return s.cleanCache.getCandidateVotes(candidate) } -func (s *liquidStakingIndexer) GetBuckets() ([]*staking.VoteBucket, error) { - vbs := []*staking.VoteBucket{} +func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { + vbs := []*Bucket{} for id, bi := range s.cleanCache.idBucketMap { bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) vb, err := convertToVoteBucket(id, bi, bt) @@ -1410,9 +1430,9 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block } // unpack event data - event := make(eventParam) - if err = abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { - return errors.Wrap(err, "unpack event data failed") + event, err := unpackEventParam(abiEvent, log) + if err != nil { + return err } // handle different kinds of event @@ -1423,7 +1443,7 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block case "BucketTypeDeactivated": err = s.handleBucketTypeDeactivatedEvent(event) case "Staked": - err = s.handleStakedEvent(event, timestamp, act.SenderAddress()) + err = s.handleStakedEvent(event, timestamp) case "Locked": err = s.handleLockedEvent(event) case "Unlocked": @@ -1440,12 +1460,28 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block err = s.handleDelegateChangedEvent(event) case "Withdrawal": err = s.handleWithdrawalEvent(event) + case "Transfer": + err = s.handleTransferEvent(event) default: err = nil } return err } +func (s *liquidStakingIndexer) handleTransferEvent(event eventParam) error { + to, err := event.indexedFieldAddress("to") + if err != nil { + return err + } + tokenID, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + + s.tokenOwner[tokenID.Uint64()] = to.String() + return nil +} + func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, timeStamp time.Time) error { amountParam, err := event.fieldUint256("amount") if err != nil { @@ -1492,8 +1528,8 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return nil } -func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp time.Time, owner address.Address) error { - tokenIDParam, err := event.fieldUint256("tokenId") +func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp time.Time) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1514,10 +1550,13 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp tim if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } + tail := len(delegateParam) - 1 + for ; tail >= 0 && delegateParam[tail] == 0; tail-- { + } bucket := BucketInfo{ TypeIndex: btIdx, - Delegate: string(delegateParam[:]), - Owner: owner.String(), + Delegate: string(delegateParam[:tail+1]), + Owner: s.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } s.putBucketInfo(tokenIDParam.Uint64(), &bucket) @@ -1725,6 +1764,22 @@ func (e eventParam) fieldAddress(name string) (common.Address, error) { return eventField[common.Address](e, name) } +func (e eventParam) indexedFieldAddress(name string) (common.Address, error) { + bytes, err := eventField[hash.Hash256](e, name) + if err != nil { + return common.Address{}, err + } + return common.BytesToAddress(bytes[:]), nil +} + +func (e eventParam) indexedFieldUint256(name string) (*big.Int, error) { + bytes, err := eventField[hash.Hash256](e, name) + if err != nil { + return nil, err + } + return big.NewInt(0).SetBytes(bytes[:]), nil +} + func (bt *BucketType) toProto() *indexpb.BucketType { return &indexpb.BucketType{ Amount: bt.Amount.String(), @@ -1758,12 +1813,19 @@ func (bt *BucketType) deserialize(b []byte) error { } func (bi *BucketInfo) toProto() *indexpb.BucketInfo { - return &indexpb.BucketInfo{ - TypeIndex: bi.TypeIndex, - UnlockedAt: timestamppb.New(*bi.UnlockedAt), - UnstakedAt: timestamppb.New(*bi.UnstakedAt), - Delegate: bi.Delegate, + pb := &indexpb.BucketInfo{ + TypeIndex: bi.TypeIndex, + Delegate: bi.Delegate, + CreatedAt: timestamppb.New(bi.CreatedAt), + Owner: bi.Owner, } + if bi.UnlockedAt != nil { + pb.UnlockedAt = timestamppb.New(*bi.UnlockedAt) + } + if bi.UnstakedAt != nil { + pb.UnstakedAt = timestamppb.New(*bi.UnstakedAt) + } + return pb } func (bi *BucketInfo) serialize() []byte { @@ -1780,11 +1842,21 @@ func (bi *BucketInfo) deserialize(b []byte) error { func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { bi.TypeIndex = p.TypeIndex - t := p.UnlockedAt.AsTime() - bi.UnlockedAt = &t - t = p.UnstakedAt.AsTime() - bi.UnstakedAt = &t + bi.CreatedAt = p.CreatedAt.AsTime() + if p.UnlockedAt != nil { + t := p.UnlockedAt.AsTime() + bi.UnlockedAt = &t + } else { + bi.UnlockedAt = nil + } + if p.UnstakedAt != nil { + t := p.UnstakedAt.AsTime() + bi.UnstakedAt = &t + } else { + bi.UnstakedAt = nil + } bi.Delegate = p.Delegate + bi.Owner = p.Owner return nil } @@ -1798,9 +1870,9 @@ func deserializeUint64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } -func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*staking.VoteBucket, error) { +func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { var err error - vb := staking.VoteBucket{ + vb := Bucket{ Index: token, StakedAmount: bt.Amount, StakedDuration: bt.Duration, @@ -1808,13 +1880,10 @@ func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*staking StakeStartTime: bi.CreatedAt, UnstakeStartTime: time.Unix(0, 0).UTC(), AutoStake: bi.UnlockedAt == nil, + Candidate: bi.Delegate, } - vb.Candidate, err = address.FromString(bi.Delegate) - if err != nil { - return nil, err - } - vb.Owner, err = address.FromString(bi.Owner) + vb.Owner, err = address.FromHex(bi.Owner) if err != nil { return nil, err } @@ -1826,3 +1895,22 @@ func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*staking } return &vb, nil } + +func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) { + event := make(eventParam) + // unpack non-indexed fields + if len(log.Data) > 0 { + if err := abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { + return nil, errors.Wrap(err, "unpack event data failed") + } + } + // unpack indexed fields + i := 0 + for _, arg := range abiEvent.Inputs { + if arg.Indexed { + i++ + event[arg.Name] = log.Topics[i] + } + } + return event, nil +} diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index eedc18d704..3319631eb5 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -4,158 +4,312 @@ import ( "context" "encoding/hex" "math/big" + "strings" "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol" + "github.com/iotexproject/iotex-core/action/protocol/account" + accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" + "github.com/iotexproject/iotex-core/action/protocol/execution" + "github.com/iotexproject/iotex-core/action/protocol/rewarding" + "github.com/iotexproject/iotex-core/action/protocol/rolldpos" + "github.com/iotexproject/iotex-core/actpool" + "github.com/iotexproject/iotex-core/blockchain" + "github.com/iotexproject/iotex-core/blockchain/block" + "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/blockchain/genesis" + "github.com/iotexproject/iotex-core/blockindex" "github.com/iotexproject/iotex-core/config" - "github.com/iotexproject/iotex-core/pkg/unit" - "github.com/iotexproject/iotex-core/server/itx" - "github.com/iotexproject/iotex-core/state" + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/state/factory" "github.com/iotexproject/iotex-core/test/identityset" "github.com/iotexproject/iotex-core/testutil" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/stretchr/testify/require" ) const ( - _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b506040518060400160405280600981526020017f4275636b65744e465400000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f424b54000000000000000000000000000000000000000000000000000000000081525081600090816200008f91906200042d565b508060019081620000a191906200042d565b505050620000c4620000b8620000e560201b60201c565b620000ed60201b60201c565b6000600660146101000a81548160ff02191690831515021790555062000514565b600033905090565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200023557607f821691505b6020821081036200024b576200024a620001ed565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620002b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000276565b620002c1868362000276565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006200030e620003086200030284620002d9565b620002e3565b620002d9565b9050919050565b6000819050919050565b6200032a83620002ed565b62000342620003398262000315565b84845462000283565b825550505050565b600090565b620003596200034a565b620003668184846200031f565b505050565b5b818110156200038e57620003826000826200034f565b6001810190506200036c565b5050565b601f821115620003dd57620003a78162000251565b620003b28462000266565b81016020851015620003c2578190505b620003da620003d18562000266565b8301826200036b565b50505b505050565b600082821c905092915050565b60006200040260001984600802620003e2565b1980831691505092915050565b60006200041d8383620003ef565b9150826002028217905092915050565b6200043882620001b3565b67ffffffffffffffff811115620004545762000453620001be565b5b6200046082546200021c565b6200046d82828562000392565b600060209050601f831160018114620004a5576000841562000490578287015190505b6200049c85826200040f565b8655506200050c565b601f198416620004b58662000251565b60005b82811015620004df57848901518255600182019150602085019450602081019050620004b8565b86831015620004ff5784890151620004fb601f891682620003ef565b8355505b6001600288020188555050505b505050505050565b61700c80620005246000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf14610a16578063e449f34114610a3f578063e985e9c514610a68578063eb0ffb2e14610aa5578063f0b56b5d14610ace578063f2fde38b14610af957610292565b8063c87b56dd146108fc578063c8e7792314610939578063cd0a02d014610962578063d0949f9914610992578063d6605fd8146109bd578063d6819bcc146109e657610292565b8063a22cb46511610113578063a22cb46514610820578063ad46fc6414610849578063b2383e5514610872578063b88d4fde1461088e578063b8f4bd7b146108b7578063bbe33ea5146108e057610292565b806378bfca101461070e5780638456cb591461074b5780638da5cb5b1461076257806393b6ef591461078d57806395d89b41146107ca5780639f7d5b00146107f557610292565b806342842e0e116101fe5780635d36598f116101b75780635d36598f146105ee5780636198e339146106175780636352211e146106405780636faa5c271461067d57806370a08231146106ba578063715018a6146106f757610292565b806342842e0e146104c3578063431cd92a146104ec57806343e06c591461052d578063597cc14a1461056a5780635c975abb1461059a5780635ceb8b5b146105c557610292565b80631338736f116102505780631338736f146103cb57806323b872dd146103f45780632dc830081461041d5780632e17de78146104465780633f4ba83a1461046f5780633fac69af1461048657610292565b8062f714ce1461029757806301ffc9a7146102c057806303459b16146102fd57806306fdde031461033a578063081812fc14610365578063095ea7b3146103a2575b600080fd5b3480156102a357600080fd5b506102be60048036038101906102b99190614f10565b610b22565b005b3480156102cc57600080fd5b506102e760048036038101906102e29190614fa8565b610bf7565b6040516102f49190614ff0565b60405180910390f35b34801561030957600080fd5b50610324600480360381019061031f919061500b565b610cd9565b6040516103319190615047565b60405180910390f35b34801561034657600080fd5b5061034f610d0a565b60405161035c91906150f2565b60405180910390f35b34801561037157600080fd5b5061038c6004803603810190610387919061500b565b610d9c565b6040516103999190615135565b60405180910390f35b3480156103ae57600080fd5b506103c960048036038101906103c4919061517c565b610de2565b005b3480156103d757600080fd5b506103f260048036038101906103ed91906151bc565b610ef9565b005b34801561040057600080fd5b5061041b600480360381019061041691906151fc565b610f73565b005b34801561042957600080fd5b50610444600480360381019061043f91906152a7565b610fd3565b005b34801561045257600080fd5b5061046d6004803603810190610468919061500b565b61103e565b005b34801561047b57600080fd5b506104846110f6565b005b34801561049257600080fd5b506104ad60048036038101906104a8919061534c565b611108565b6040516104ba9190615519565b60405180910390f35b3480156104cf57600080fd5b506104ea60048036038101906104e591906151fc565b6112cb565b005b3480156104f857600080fd5b50610513600480360381019061050e919061500b565b6112eb565b60405161052495949392919061554a565b60405180910390f35b34801561053957600080fd5b50610554600480360381019061054f91906151bc565b611378565b6040516105619190614ff0565b60405180910390f35b610584600480360381019061057f91906152a7565b611394565b6040516105919190615047565b60405180910390f35b3480156105a657600080fd5b506105af611413565b6040516105bc9190614ff0565b60405180910390f35b3480156105d157600080fd5b506105ec60048036038101906105e791906155f3565b61142a565b005b3480156105fa57600080fd5b5061061560048036038101906106109190615653565b6114e0565b005b34801561062357600080fd5b5061063e6004803603810190610639919061500b565b611589565b005b34801561064c57600080fd5b506106676004803603810190610662919061500b565b6115f6565b6040516106749190615135565b60405180910390f35b34801561068957600080fd5b506106a4600480360381019061069f919061534c565b61167c565b6040516106b19190615519565b60405180910390f35b3480156106c657600080fd5b506106e160048036038101906106dc91906156a0565b61183f565b6040516106ee9190615047565b60405180910390f35b34801561070357600080fd5b5061070c6118f6565b005b34801561071a57600080fd5b50610735600480360381019061073091906151bc565b61190a565b60405161074291906157be565b60405180910390f35b34801561075757600080fd5b50610760611a50565b005b34801561076e57600080fd5b50610777611a62565b6040516107849190615135565b60405180910390f35b34801561079957600080fd5b506107b460048036038101906107af919061500b565b611a8c565b6040516107c19190615047565b60405180910390f35b3480156107d657600080fd5b506107df611ac8565b6040516107ec91906150f2565b60405180910390f35b34801561080157600080fd5b5061080a611b5a565b6040516108179190615047565b60405180910390f35b34801561082c57600080fd5b506108476004803603810190610842919061580c565b611b67565b005b34801561085557600080fd5b50610870600480360381019061086b919061584c565b611b7d565b005b61088c600480360381019061088791906151bc565b611c28565b005b34801561089a57600080fd5b506108b560048036038101906108b091906159dc565b611dfc565b005b3480156108c357600080fd5b506108de60048036038101906108d99190615a5f565b611e5e565b005b6108fa60048036038101906108f591906155f3565b611f6f565b005b34801561090857600080fd5b50610923600480360381019061091e919061500b565b6122e9565b60405161093091906150f2565b60405180910390f35b34801561094557600080fd5b50610960600480360381019061095b91906151bc565b612351565b005b61097c60048036038101906109779190615abf565b6124d4565b6040516109899190615047565b60405180910390f35b34801561099e57600080fd5b506109a76125cc565b6040516109b49190615047565b60405180910390f35b3480156109c957600080fd5b506109e460048036038101906109df91906151bc565b6125f0565b005b610a0060048036038101906109fb9190615be9565b6127b9565b604051610a0d9190615047565b60405180910390f35b348015610a2257600080fd5b50610a3d6004803603810190610a3891906151bc565b6128da565b005b348015610a4b57600080fd5b50610a666004803603810190610a619190615653565b612952565b005b348015610a7457600080fd5b50610a8f6004803603810190610a8a9190615c58565b612a46565b604051610a9c9190614ff0565b60405180910390f35b348015610ab157600080fd5b50610acc6004803603810190610ac791906151bc565b612ada565b005b348015610ada57600080fd5b50610ae3612b72565b604051610af09190615047565b60405180910390f35b348015610b0557600080fd5b50610b206004803603810190610b1b91906156a0565b612b78565b005b610b2a612bfb565b81610b3481612c45565b60006008600085815260200190815260200160002090506000610b5a8260020154612cbe565b14610b9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b9190615ce4565b60405180910390fd5b610ba384612d37565b610bad8184612e85565b8273ffffffffffffffffffffffffffffffffffffffff16847fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee60405160405180910390a350505050565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610cc257507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610cd25750610cd182612f65565b5b9050919050565b6000610ce482612fcf565b610d036008600084815260200190815260200160002060020154612cbe565b9050919050565b606060008054610d1990615d33565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4590615d33565b8015610d925780601f10610d6757610100808354040283529160200191610d92565b820191906000526020600020905b815481529060010190602001808311610d7557829003601f168201915b5050505050905090565b6000610da78261301a565b6004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000610ded826115f6565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e5d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e5490615dd6565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16610e7c613065565b73ffffffffffffffffffffffffffffffffffffffff161480610eab5750610eaa81610ea5613065565b612a46565b5b610eea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ee190615e68565b60405180910390fd5b610ef4838361306d565b505050565b610f01612bfb565b81610f0b81612c45565b6000600860008581526020019081526020016000209050610f2b81613126565b610f358184613176565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610f659190615047565b60405180910390a250505050565b610f84610f7e613065565b826133b7565b610fc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fba90615efa565b60405180910390fd5b610fce83838361344c565b505050565b610fdb612bfb565b81610fe581612c45565b6110016008600085815260200190815260200160002083613745565b827ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c836040516110319190615f1a565b60405180910390a2505050565b611046612bfb565b8061105081612c45565b600060086000848152602001908152602001600020905061107081613126565b600061107b82613ae7565b146110bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b290615f81565b60405180910390fd5b6110c481613b91565b827f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b260405160405180910390a2505050565b6110fe613c78565b611106613cf6565b565b60608282905067ffffffffffffffff811115611127576111266158b1565b5b60405190808252806020026020018201604052801561115a57816020015b60608152602001906001900390816111455790505b5090506000611167611b5a565b905060005b848490508110156112c3578167ffffffffffffffff811115611191576111906158b1565b5b6040519080825280602002602001820160405280156111bf5781602001602082028036833780820191505090505b508382815181106111d3576111d2615fa1565b5b60200260200101819052506000600960008787858181106111f7576111f6615fa1565b5b905060200201602081019061120c9190615fd0565b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020905060005b838110156112b1578160008281526020019081526020016000205485848151811061127b5761127a615fa1565b5b6020026020010151828151811061129557611294615fa1565b5b6020026020010181815250506112aa81613d59565b905061124d565b50506112bc81613d59565b905061116c565b505092915050565b6112e683838360405180602001604052806000815250611dfc565b505050565b60008060008060006112fc86612fcf565b60006008600088815260200190815260200160002090506000600b82600001548154811061132d5761132c615fa1565b5b9060005260206000209060030201905080600001548160010154836001015484600201548560030160009054906101000a900460a01b96509650965096509650505091939590929450565b600061138c6113878484613d66565b613de5565b905092915050565b600061139e612bfb565b600034905060006113af8286613d66565b90506113ba81613e17565b6113c48185613e62565b60006007549050807f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8685896040516113ff93929190615ffd565b60405180910390a280935050505092915050565b6000600660149054906101000a900460ff16905090565b611432612bfb565b60008060005b858590508110156114d85785858281811061145657611455615fa1565b5b90506020020135925061146883612c45565b60086000848152602001908152602001600020915061148682613126565b6114908285613176565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516114c09190615047565b60405180910390a26114d181613d59565b9050611438565b505050505050565b6114e8612bfb565b60008060005b848490508110156115825784848281811061150c5761150b615fa1565b5b90506020020135925061151e83612c45565b60086000848152602001908152602001600020915061153c8261400e565b6115458261405e565b827ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184260405160405180910390a261157b81613d59565b90506114ee565b5050505050565b611591612bfb565b8061159b81612c45565b60006008600084815260200190815260200160002090506115bb8161400e565b6115c48161405e565b827ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184260405160405180910390a2505050565b600080611602836141ed565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611673576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161166a90616080565b60405180910390fd5b80915050919050565b60608282905067ffffffffffffffff81111561169b5761169a6158b1565b5b6040519080825280602002602001820160405280156116ce57816020015b60608152602001906001900390816116b95790505b50905060006116db611b5a565b905060005b84849050811015611837578167ffffffffffffffff811115611705576117046158b1565b5b6040519080825280602002602001820160405280156117335781602001602082028036833780820191505090505b5083828151811061174757611746615fa1565b5b60200260200101819052506000600a600087878581811061176b5761176a615fa1565b5b90506020020160208101906117809190615fd0565b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020905060005b8381101561182557816000828152602001908152602001600020548584815181106117ef576117ee615fa1565b5b6020026020010151828151811061180957611808615fa1565b5b60200260200101818152505061181e81613d59565b90506117c1565b505061183081613d59565b90506116e0565b505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036118af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118a690616112565b60405180910390fd5b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6118fe613c78565b611908600061422a565b565b606060008211801561192e575061191f611b5a565b828461192b9190616161565b11155b61196d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611964906161e1565b60405180910390fd5b8167ffffffffffffffff811115611987576119866158b1565b5b6040519080825280602002602001820160405280156119c057816020015b6119ad614e47565b8152602001906001900390816119a55790505b50905060005b82811015611a4957600b818501815481106119e4576119e3615fa1565b5b90600052602060002090600302016040518060600160405290816000820154815260200160018201548152602001600282015481525050828281518110611a2e57611a2d615fa1565b5b6020026020010181905250611a4281613d59565b90506119c6565b5092915050565b611a58613c78565b611a606142f0565b565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000611a9782612fcf565b6000600860008481526020019081526020016000209050611ab781613126565b611ac081613ae7565b915050919050565b606060018054611ad790615d33565b80601f0160208091040260200160405190810160405280929190818152602001828054611b0390615d33565b8015611b505780601f10611b2557610100808354040283529160200191611b50565b820191906000526020600020905b815481529060010190602001808311611b3357829003601f168201915b5050505050905090565b6000600b80549050905090565b611b79611b72613065565b8383614353565b5050565b611b85612bfb565b600080600090505b84849050811015611c2157848482818110611bab57611baa615fa1565b5b905060200201359150611bbd82612c45565b611bd96008600084815260200190815260200160002084613745565b817ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c84604051611c099190615f1a565b60405180910390a2611c1a81613d59565b9050611b8d565b5050505050565b611c30612bfb565b81611c3a81612c45565b6000600860008581526020019081526020016000209050611c5a8161400e565b6000816000015490506000600b8281548110611c7957611c78615fa1565b5b9060005260206000209060030201905084816000015434611c9a9190616161565b14611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd19061624d565b60405180910390fd5b611d46600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550611dbc838683600101546144cc565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d86604051611dec9190615047565b60405180910390a2505050505050565b611e0d611e07613065565b836133b7565b611e4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4390615efa565b60405180910390fd5b611e58848484846145c5565b50505050565b611e66612bfb565b60008060005b85859050811015611f6757858582818110611e8a57611e89615fa1565b5b905060200201359250611e9c83612c45565b6008600084815260200190815260200160002091506000611ec08360020154612cbe565b14611f00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ef790615ce4565b60405180910390fd5b611f0983612d37565b611f138285612e85565b8373ffffffffffffffffffffffffffffffffffffffff16837fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee60405160405180910390a3611f6081613d59565b9050611e6c565b505050505050565b611f77612bfb565b60018383905011611fbd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611fb4906162b9565b60405180910390fd5b60003490506000806000808787905090505b60008111156122df57611fe1816144bf565b9050878782818110611ff657611ff5615fa1565b5b90506020020135935061200884612c45565b60086000858152602001908152602001600020925061202683613126565b60008360000154905060008460030160009054906101000a900460a01b9050600b828154811061205957612058615fa1565b5b9060005260206000209060030201935083600101548810156120b0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a790616325565b60405180910390fd5b8360000154876120c09190616161565b96506120cf8560010154614621565b1561218a5761212f600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008481526020019081526020016000208190555061223c565b6121e5600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055505b600083146122525761224d86612d37565b6122d8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff856001018190555061228685888a6144cc565b89896040516122969291906163ba565b60405180910390207fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12888a6040516122cf9291906163d3565b60405180910390a25b5050611fcf565b5050505050505050565b60606122f48261301a565b60006122fe61464e565b9050600081511161231e5760405180602001604052806000815250612349565b8061232884614665565b604051602001612339929190616438565b6040516020818303038152906040525b915050919050565b612359613c78565b6000820361239c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612393906164a8565b60405180910390fd5b6000600c600084815260200190815260200160002060008381526020019081526020016000205414612403576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123fa90616514565b60405180910390fd5b600b60405180606001604052808481526020018381526020014381525090806001815401808255809150506001900390600052602060002090600302016000909190919091506000820151816000015560208201518160010155604082015181600201555050600b80549050600c60008481526020019081526020016000206000838152602001908152602001600020819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b782826040516124c89291906163d3565b60405180910390a15050565b60006124de612bfb565b6000821180156124f857503482866124f69190616534565b145b612537576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252e906161e1565b60405180910390fd5b60006125438686613d66565b905061254e81613e17565b600160075401915060005b838110156125c25761256b8286613e62565b80836125779190616161565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8689896040516125aa93929190615ffd565b60405180910390a26125bb81613d59565b9050612559565b5050949350505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b6125f8612bfb565b8161260281612c45565b60006008600085815260200190815260200160002090506126228161400e565b6000816000015490506000600b828154811061264157612640615fa1565b5b9060005260206000209060030201905080600101548511612697576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161268e9061624d565b60405180910390fd5b612703600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008560030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550612779838260000154876144cc565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea4866040516127a99190615047565b60405180910390a2505050505050565b60006127c3612bfb565b348251856127d19190616534565b14612811576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612808906161e1565b60405180910390fd5b600061281d8585613d66565b905061282881613e17565b600160075401915060005b83518110156128d1576128608285838151811061285357612852615fa1565b5b6020026020010151613e62565b808361286c9190616161565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a8583815181106128a05761289f615fa1565b5b602002602001015188886040516128b993929190615ffd565b60405180910390a26128ca81613d59565b9050612833565b50509392505050565b6128e2613c78565b43600b6128ef8484613d66565b81548110612900576128ff615fa1565b5b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b782826040516129469291906163d3565b60405180910390a15050565b61295a612bfb565b60008060005b84849050811015612a3f5784848281811061297e5761297d615fa1565b5b90506020020135925061299083612c45565b6008600084815260200190815260200160002091506129ae82613126565b60006129b983613ae7565b146129f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f090615f81565b60405180910390fd5b612a0282613b91565b827f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b260405160405180910390a2612a3881613d59565b9050612960565b5050505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b612ae2613c78565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600b612b0f8484613d66565b81548110612b2057612b1f615fa1565b5b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051612b669291906163d3565b60405180910390a15050565b61ca8081565b612b80613c78565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612bef576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612be6906165e8565b60405180910390fd5b612bf88161422a565b50565b612c03611413565b15612c43576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c3a90616654565b60405180910390fd5b565b612c4e816115f6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cbb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cb2906166c0565b60405180910390fd5b50565b6000612cc982614621565b612d08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cff9061672c565b60405180910390fd5b600061ca8083612d189190616161565b9050438111612d2b576000915050612d32565b4381039150505b919050565b6000612d42826115f6565b9050612d52816000846001614733565b612d5b826115f6565b90506004600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506002600083815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905581600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4612e8181600084600161481e565b5050565b6000600b836000015481548110612e9f57612e9e615fa1565b5b906000526020600020906003020160000154905060008273ffffffffffffffffffffffffffffffffffffffff1682604051612ed99061677d565b60006040518083038185875af1925050503d8060008114612f16576040519150601f19603f3d011682016040523d82523d6000602084013e612f1b565b606091505b5050905080612f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f56906167de565b60405180910390fd5b50505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b612fd881614824565b613017576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161300e90616080565b60405180910390fd5b50565b61302381614824565b613062576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161305990616080565b60405180910390fd5b50565b600033905090565b816004600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff166130e0836115f6565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6131338160020154614621565b15613173576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161316a9061684a565b60405180910390fd5b50565b60008260000154905060008360030160009054906101000a900460a01b905061319e84613ae7565b8310156131e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131d790616325565b60405180910390fd5b6000613211600b84815481106131f9576131f8615fa1565b5b90600052602060002090600302016000015485613d66565b905061321c81613e17565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85600101819055506132a0600960008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000858152602001908152602001600020546144bf565b600960008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008581526020019081526020016000208190555080856000018190555061335a600a60008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083815260200190815260200160002054613d59565b600a60008473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000838152602001908152602001600020819055505050505050565b6000806133c3836115f6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061340557506134048185612a46565b5b8061344357508373ffffffffffffffffffffffffffffffffffffffff1661342b84610d9c565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661346c826115f6565b73ffffffffffffffffffffffffffffffffffffffff16146134c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016134b9906168dc565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613531576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135289061696e565b60405180910390fd5b61353e8383836001614733565b8273ffffffffffffffffffffffffffffffffffffffff1661355e826115f6565b73ffffffffffffffffffffffffffffffffffffffff16146135b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016135ab906168dc565b60405180910390fd5b6004600082815260200190815260200160002060006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4613740838383600161481e565b505050565b61374e82613126565b60008260000154905060008360030160009054906101000a900460a01b90508273ffffffffffffffffffffffffffffffffffffffff19168173ffffffffffffffffffffffffffffffffffffffff1916036137dd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137d49061624d565b60405180910390fd5b6137ea8460010154614621565b156139565761384a600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055506138fb600960008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600960008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550613ab9565b6139b1600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550613a62600a60008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600a60008573ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020819055505b828460030160006101000a8154816bffffffffffffffffffffffff021916908360a01c021790555050505050565b60008082600101549050613afa81614621565b613b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613b30906169da565b60405180910390fd5b6000600b846000015481548110613b5357613b52615fa1565b5b90600052602060002090600302016001015482613b709190616161565b9050438111613b8457600092505050613b8c565b438103925050505b919050565b438160020181905550613c0a600960008360030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083600001548152602001908152602001600020546144bf565b600960008360030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000836000015481526020019081526020016000208190555050565b613c80613065565b73ffffffffffffffffffffffffffffffffffffffff16613c9e611a62565b73ffffffffffffffffffffffffffffffffffffffff1614613cf4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613ceb90616a46565b60405180910390fd5b565b613cfe614865565b6000600660146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa613d42613065565b604051613d4f9190615135565b60405180910390a1565b6000600182019050919050565b600080600c6000858152602001908152602001600020600084815260200190815260200160002054905060008111613dd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613dca90616ab2565b60405180910390fd5b613ddc816144bf565b91505092915050565b600043600b8381548110613dfc57613dfb615fa1565b5b90600052602060002090600302016002015411159050919050565b613e2081613de5565b613e5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613e5690616b1e565b60405180910390fd5b50565b613e6d600754613d59565b60078190555060405180608001604052808381526020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81526020017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81526020018273ffffffffffffffffffffffffffffffffffffffff191681525060086000600754815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a8154816bffffffffffffffffffffffff021916908360a01c0217905550905050613fa8600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008481526020019081526020016000208190555061400a336007546148ae565b5050565b61401b8160010154614621565b1561405b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161405290616b8a565b60405180910390fd5b50565b60008160000154905060008260030160009054906101000a900460a01b90504383600101819055506140e1600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff191681526020019081526020016000206000848152602001908152602001600020546144bf565b600a60008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550614192600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002054613d59565b600960008373ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600084815260200190815260200160002081905550505050565b60006002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6142f8612bfb565b6001600660146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861433c613065565b6040516143499190615135565b60405180910390a1565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036143c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016143b890616bf6565b60405180910390fd5b80600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516144b29190614ff0565b60405180910390a3505050565b6000600182039050919050565b60006144d88383613d66565b90506144e381613e17565b61454f600a60008660030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff19168152602001908152602001600020600083815260200190815260200160002054613d59565b600a60008660030160009054906101000a900460a01b73ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff1916815260200190815260200160002060008381526020019081526020016000208190555080846000018190555050505050565b6145d084848461344c565b6145dc848484846148cc565b61461b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161461290616c88565b60405180910390fd5b50505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214159050919050565b606060405180602001604052806000815250905090565b60606000600161467484614a53565b01905060008167ffffffffffffffff811115614693576146926158b1565b5b6040519080825280601f01601f1916602001820160405280156146c55781602001600182028036833780820191505090505b509050600082602001820190505b600115614728578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161471c5761471b616ca8565b5b049450600085036146d3575b819350505050919050565b60018114614776576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161476d90616d23565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806147cd57506147cb6008600084815260200190815260200160002060020154614621565b155b61480c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161480390616d8f565b60405180910390fd5b61481884848484614ba6565b50505050565b50505050565b60008073ffffffffffffffffffffffffffffffffffffffff16614846836141ed565b73ffffffffffffffffffffffffffffffffffffffff1614159050919050565b61486d611413565b6148ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016148a390616dfb565b60405180910390fd5b565b6148c8828260405180602001604052806000815250614bac565b5050565b60006148ed8473ffffffffffffffffffffffffffffffffffffffff16614c07565b15614a46578373ffffffffffffffffffffffffffffffffffffffff1663150b7a02614916613065565b8786866040518563ffffffff1660e01b81526004016149389493929190616e70565b6020604051808303816000875af192505050801561497457506040513d601f19601f820116820180604052508101906149719190616ed1565b60015b6149f6573d80600081146149a4576040519150601f19603f3d011682016040523d82523d6000602084013e6149a9565b606091505b5060008151036149ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016149e590616c88565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614915050614a4b565b600190505b949350505050565b600080600090507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310614ab1577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381614aa757614aa6616ca8565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310614aee576d04ee2d6d415b85acef81000000008381614ae457614ae3616ca8565b5b0492506020810190505b662386f26fc100008310614b1d57662386f26fc100008381614b1357614b12616ca8565b5b0492506010810190505b6305f5e1008310614b46576305f5e1008381614b3c57614b3b616ca8565b5b0492506008810190505b6127108310614b6b576127108381614b6157614b60616ca8565b5b0492506004810190505b60648310614b8e5760648381614b8457614b83616ca8565b5b0492506002810190505b600a8310614b9d576001810190505b80915050919050565b50505050565b614bb68383614c2a565b614bc360008484846148cc565b614c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614bf990616c88565b60405180910390fd5b505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603614c99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614c9090616f4a565b60405180910390fd5b614ca281614824565b15614ce2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614cd990616fb6565b60405180910390fd5b614cf0600083836001614733565b614cf981614824565b15614d39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614d3090616fb6565b60405180910390fd5b6001600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4614e4360008383600161481e565b5050565b60405180606001604052806000815260200160008152602001600081525090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b614e8f81614e7c565b8114614e9a57600080fd5b50565b600081359050614eac81614e86565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000614edd82614eb2565b9050919050565b614eed81614ed2565b8114614ef857600080fd5b50565b600081359050614f0a81614ee4565b92915050565b60008060408385031215614f2757614f26614e72565b5b6000614f3585828601614e9d565b9250506020614f4685828601614efb565b9150509250929050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b614f8581614f50565b8114614f9057600080fd5b50565b600081359050614fa281614f7c565b92915050565b600060208284031215614fbe57614fbd614e72565b5b6000614fcc84828501614f93565b91505092915050565b60008115159050919050565b614fea81614fd5565b82525050565b60006020820190506150056000830184614fe1565b92915050565b60006020828403121561502157615020614e72565b5b600061502f84828501614e9d565b91505092915050565b61504181614e7c565b82525050565b600060208201905061505c6000830184615038565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561509c578082015181840152602081019050615081565b60008484015250505050565b6000601f19601f8301169050919050565b60006150c482615062565b6150ce818561506d565b93506150de81856020860161507e565b6150e7816150a8565b840191505092915050565b6000602082019050818103600083015261510c81846150b9565b905092915050565b600061511f82614eb2565b9050919050565b61512f81615114565b82525050565b600060208201905061514a6000830184615126565b92915050565b61515981615114565b811461516457600080fd5b50565b60008135905061517681615150565b92915050565b6000806040838503121561519357615192614e72565b5b60006151a185828601615167565b92505060206151b285828601614e9d565b9150509250929050565b600080604083850312156151d3576151d2614e72565b5b60006151e185828601614e9d565b92505060206151f285828601614e9d565b9150509250929050565b60008060006060848603121561521557615214614e72565b5b600061522386828701615167565b935050602061523486828701615167565b925050604061524586828701614e9d565b9150509250925092565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b6152848161524f565b811461528f57600080fd5b50565b6000813590506152a18161527b565b92915050565b600080604083850312156152be576152bd614e72565b5b60006152cc85828601614e9d565b92505060206152dd85828601615292565b9150509250929050565b600080fd5b600080fd5b600080fd5b60008083601f84011261530c5761530b6152e7565b5b8235905067ffffffffffffffff811115615329576153286152ec565b5b602083019150836020820283011115615345576153446152f1565b5b9250929050565b6000806020838503121561536357615362614e72565b5b600083013567ffffffffffffffff81111561538157615380614e77565b5b61538d858286016152f6565b92509250509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6153fa81614e7c565b82525050565b600061540c83836153f1565b60208301905092915050565b6000602082019050919050565b6000615430826153c5565b61543a81856153d0565b9350615445836153e1565b8060005b8381101561547657815161545d8882615400565b975061546883615418565b925050600181019050615449565b5085935050505092915050565b600061548f8383615425565b905092915050565b6000602082019050919050565b60006154af82615399565b6154b981856153a4565b9350836020820285016154cb856153b5565b8060005b8581101561550757848403895281516154e88582615483565b94506154f383615497565b925060208a019950506001810190506154cf565b50829750879550505050505092915050565b6000602082019050818103600083015261553381846154a4565b905092915050565b6155448161524f565b82525050565b600060a08201905061555f6000830188615038565b61556c6020830187615038565b6155796040830186615038565b6155866060830185615038565b615593608083018461553b565b9695505050505050565b60008083601f8401126155b3576155b26152e7565b5b8235905067ffffffffffffffff8111156155d0576155cf6152ec565b5b6020830191508360208202830111156155ec576155eb6152f1565b5b9250929050565b60008060006040848603121561560c5761560b614e72565b5b600084013567ffffffffffffffff81111561562a57615629614e77565b5b6156368682870161559d565b9350935050602061564986828701614e9d565b9150509250925092565b6000806020838503121561566a57615669614e72565b5b600083013567ffffffffffffffff81111561568857615687614e77565b5b6156948582860161559d565b92509250509250929050565b6000602082840312156156b6576156b5614e72565b5b60006156c484828501615167565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60608201600082015161570f60008501826153f1565b50602082015161572260208501826153f1565b50604082015161573560408501826153f1565b50505050565b600061574783836156f9565b60608301905092915050565b6000602082019050919050565b600061576b826156cd565b61577581856156d8565b9350615780836156e9565b8060005b838110156157b1578151615798888261573b565b97506157a383615753565b925050600181019050615784565b5085935050505092915050565b600060208201905081810360008301526157d88184615760565b905092915050565b6157e981614fd5565b81146157f457600080fd5b50565b600081359050615806816157e0565b92915050565b6000806040838503121561582357615822614e72565b5b600061583185828601615167565b9250506020615842858286016157f7565b9150509250929050565b60008060006040848603121561586557615864614e72565b5b600084013567ffffffffffffffff81111561588357615882614e77565b5b61588f8682870161559d565b935093505060206158a286828701615292565b9150509250925092565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6158e9826150a8565b810181811067ffffffffffffffff82111715615908576159076158b1565b5b80604052505050565b600061591b614e68565b905061592782826158e0565b919050565b600067ffffffffffffffff821115615947576159466158b1565b5b615950826150a8565b9050602081019050919050565b82818337600083830152505050565b600061597f61597a8461592c565b615911565b90508281526020810184848401111561599b5761599a6158ac565b5b6159a684828561595d565b509392505050565b600082601f8301126159c3576159c26152e7565b5b81356159d384826020860161596c565b91505092915050565b600080600080608085870312156159f6576159f5614e72565b5b6000615a0487828801615167565b9450506020615a1587828801615167565b9350506040615a2687828801614e9d565b925050606085013567ffffffffffffffff811115615a4757615a46614e77565b5b615a53878288016159ae565b91505092959194509250565b600080600060408486031215615a7857615a77614e72565b5b600084013567ffffffffffffffff811115615a9657615a95614e77565b5b615aa28682870161559d565b93509350506020615ab586828701614efb565b9150509250925092565b60008060008060808587031215615ad957615ad8614e72565b5b6000615ae787828801614e9d565b9450506020615af887828801614e9d565b9350506040615b0987828801615292565b9250506060615b1a87828801614e9d565b91505092959194509250565b600067ffffffffffffffff821115615b4157615b406158b1565b5b602082029050602081019050919050565b6000615b65615b6084615b26565b615911565b90508083825260208201905060208402830185811115615b8857615b876152f1565b5b835b81811015615bb15780615b9d8882615292565b845260208401935050602081019050615b8a565b5050509392505050565b600082601f830112615bd057615bcf6152e7565b5b8135615be0848260208601615b52565b91505092915050565b600080600060608486031215615c0257615c01614e72565b5b6000615c1086828701614e9d565b9350506020615c2186828701614e9d565b925050604084013567ffffffffffffffff811115615c4257615c41614e77565b5b615c4e86828701615bbb565b9150509250925092565b60008060408385031215615c6f57615c6e614e72565b5b6000615c7d85828601615167565b9250506020615c8e85828601615167565b9150509250929050565b7f6e6f7420726561647920746f2077697468647261770000000000000000000000600082015250565b6000615cce60158361506d565b9150615cd982615c98565b602082019050919050565b60006020820190508181036000830152615cfd81615cc1565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680615d4b57607f821691505b602082108103615d5e57615d5d615d04565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000615dc060218361506d565b9150615dcb82615d64565b604082019050919050565b60006020820190508181036000830152615def81615db3565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60008201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015250565b6000615e52603d8361506d565b9150615e5d82615df6565b604082019050919050565b60006020820190508181036000830152615e8181615e45565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560008201527f72206f7220617070726f76656400000000000000000000000000000000000000602082015250565b6000615ee4602d8361506d565b9150615eef82615e88565b604082019050919050565b60006020820190508181036000830152615f1381615ed7565b9050919050565b6000602082019050615f2f600083018461553b565b92915050565b7f6e6f7420726561647920746f20756e7374616b65000000000000000000000000600082015250565b6000615f6b60148361506d565b9150615f7682615f35565b602082019050919050565b60006020820190508181036000830152615f9a81615f5e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215615fe657615fe5614e72565b5b6000615ff484828501615292565b91505092915050565b6000606082019050616012600083018661553b565b61601f6020830185615038565b61602c6040830184615038565b949350505050565b7f4552433732313a20696e76616c696420746f6b656e2049440000000000000000600082015250565b600061606a60188361506d565b915061607582616034565b602082019050919050565b600060208201905081810360008301526160998161605d565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f74206120766160008201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b60006160fc60298361506d565b9150616107826160a0565b604082019050919050565b6000602082019050818103600083015261612b816160ef565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061616c82614e7c565b915061617783614e7c565b925082820190508082111561618f5761618e616132565b5b92915050565b7f696e76616c696420706172616d65746572730000000000000000000000000000600082015250565b60006161cb60128361506d565b91506161d682616195565b602082019050919050565b600060208201905081810360008301526161fa816161be565b9050919050565b7f696e76616c6964206f7065726174696f6e000000000000000000000000000000600082015250565b600061623760118361506d565b915061624282616201565b602082019050919050565b600060208201905081810360008301526162668161622a565b9050919050565b7f696e76616c6964206c656e677468000000000000000000000000000000000000600082015250565b60006162a3600e8361506d565b91506162ae8261626d565b602082019050919050565b600060208201905081810360008301526162d281616296565b9050919050565b7f696e76616c6964206475726174696f6e00000000000000000000000000000000600082015250565b600061630f60108361506d565b915061631a826162d9565b602082019050919050565b6000602082019050818103600083015261633e81616302565b9050919050565b600081905092915050565b600080fd5b82818337505050565b600061636a8385616345565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561639d5761639c616350565b5b6020830292506163ae838584616355565b82840190509392505050565b60006163c782848661635e565b91508190509392505050565b60006040820190506163e86000830185615038565b6163f56020830184615038565b9392505050565b600081905092915050565b600061641282615062565b61641c81856163fc565b935061642c81856020860161507e565b80840191505092915050565b60006164448285616407565b91506164508284616407565b91508190509392505050565b7f616d6f756e7420697320696e76616c6964000000000000000000000000000000600082015250565b600061649260118361506d565b915061649d8261645c565b602082019050919050565b600060208201905081810360008301526164c181616485565b9050919050565b7f6475706c6963617465206275636b657420747970650000000000000000000000600082015250565b60006164fe60158361506d565b9150616509826164c8565b602082019050919050565b6000602082019050818103600083015261652d816164f1565b9050919050565b600061653f82614e7c565b915061654a83614e7c565b925082820261655881614e7c565b9150828204841483151761656f5761656e616132565b5b5092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006165d260268361506d565b91506165dd82616576565b604082019050919050565b60006020820190508181036000830152616601816165c5565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b600061663e60108361506d565b915061664982616608565b602082019050919050565b6000602082019050818103600083015261666d81616631565b9050919050565b7f6e6f74206f776e65720000000000000000000000000000000000000000000000600082015250565b60006166aa60098361506d565b91506166b582616674565b602082019050919050565b600060208201905081810360008301526166d98161669d565b9050919050565b7f6e6f7420616e20756e7374616b6564206275636b657400000000000000000000600082015250565b600061671660168361506d565b9150616721826166e0565b602082019050919050565b6000602082019050818103600083015261674581616709565b9050919050565b600081905092915050565b50565b600061676760008361674c565b915061677282616757565b600082019050919050565b60006167888261675a565b9150819050919050565b7f6661696c656420746f207472616e736665720000000000000000000000000000600082015250565b60006167c860128361506d565b91506167d382616792565b602082019050919050565b600060208201905081810360008301526167f7816167bb565b9050919050565b7f6e6f742061207374616b656420746f6b656e0000000000000000000000000000600082015250565b600061683460128361506d565b915061683f826167fe565b602082019050919050565b6000602082019050818103600083015261686381616827565b9050919050565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b60006168c660258361506d565b91506168d18261686a565b604082019050919050565b600060208201905081810360008301526168f5816168b9565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061695860248361506d565b9150616963826168fc565b604082019050919050565b600060208201905081810360008301526169878161694b565b9050919050565b7f6e6f7420616e20756e6c6f636b6564206275636b657400000000000000000000600082015250565b60006169c460168361506d565b91506169cf8261698e565b602082019050919050565b600060208201905081810360008301526169f3816169b7565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000616a3060208361506d565b9150616a3b826169fa565b602082019050919050565b60006020820190508181036000830152616a5f81616a23565b9050919050565b7f696e76616c6964206275636b6574207479706500000000000000000000000000600082015250565b6000616a9c60138361506d565b9150616aa782616a66565b602082019050919050565b60006020820190508181036000830152616acb81616a8f565b9050919050565b7f696e616374697665206275636b65742074797065000000000000000000000000600082015250565b6000616b0860148361506d565b9150616b1382616ad2565b602082019050919050565b60006020820190508181036000830152616b3781616afb565b9050919050565b7f6e6f742061206c6f636b656420746f6b656e0000000000000000000000000000600082015250565b6000616b7460128361506d565b9150616b7f82616b3e565b602082019050919050565b60006020820190508181036000830152616ba381616b67565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b6000616be060198361506d565b9150616beb82616baa565b602082019050919050565b60006020820190508181036000830152616c0f81616bd3565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b6000616c7260328361506d565b9150616c7d82616c16565b604082019050919050565b60006020820190508181036000830152616ca181616c65565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f6261746368207472616e73666572206973206e6f7420737570706f7274656400600082015250565b6000616d0d601f8361506d565b9150616d1882616cd7565b602082019050919050565b60006020820190508181036000830152616d3c81616d00565b9050919050565b7f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000600082015250565b6000616d79601e8361506d565b9150616d8482616d43565b602082019050919050565b60006020820190508181036000830152616da881616d6c565b9050919050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000616de560148361506d565b9150616df082616daf565b602082019050919050565b60006020820190508181036000830152616e1481616dd8565b9050919050565b600081519050919050565b600082825260208201905092915050565b6000616e4282616e1b565b616e4c8185616e26565b9350616e5c81856020860161507e565b616e65816150a8565b840191505092915050565b6000608082019050616e856000830187615126565b616e926020830186615126565b616e9f6040830185615038565b8181036060830152616eb18184616e37565b905095945050505050565b600081519050616ecb81614f7c565b92915050565b600060208284031215616ee757616ee6614e72565b5b6000616ef584828501616ebc565b91505092915050565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b6000616f3460208361506d565b9150616f3f82616efe565b602082019050919050565b60006020820190508181036000830152616f6381616f27565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b6000616fa0601c8361506d565b9150616fab82616f6a565b602082019050919050565b60006020820190508181036000830152616fcf81616f93565b905091905056fea2646970667358221220d4fb1d4a5f31b44bb4783b1e7268c7deb8646c92668ae8c0866d990b17ca737864736f6c63430008120033` + _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b2366004613430565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613476565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613493565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134fc565b34801561034a57600080fd5b5061035e610359366004613493565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b761039136600461350f565b610ab4565b3480156103a257600080fd5b506102b76103b136600461353b565b610bc9565b3480156103c257600080fd5b506102b76103d136600461355d565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135bb565b610c6d565b34801561040257600080fd5b506102b7610411366004613493565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b610446366004613632565b610d9c565b6040516102e59190613673565b34801561046457600080fd5b506102b761047336600461355d565b610f18565b34801561048457600080fd5b50610498610493366004613493565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e536600461353b565b610fa9565b61030e6104f83660046135bb565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136fd565b61103a565b34801561054857600080fd5b506102b7610557366004613632565b6110e1565b34801561056857600080fd5b506102b7610577366004613493565b611177565b34801561058857600080fd5b5061035e610597366004613493565b6111d9565b3480156105a857600080fd5b5061044b6105b7366004613632565b611239565b3480156105c857600080fd5b5061030e6105d7366004613748565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c36600461353b565b611445565b6040516102e59190613765565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613493565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137be565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137f1565b6115d3565b6102b76106e936600461353b565b61166a565b3480156106fa57600080fd5b506102b761070936600461388a565b611772565b34801561071a57600080fd5b506102b761072936600461394d565b6117aa565b6102b761073c3660046136fd565b611899565b34801561074d57600080fd5b5061033161075c366004613493565b611ab3565b34801561076d57600080fd5b506102b761077c36600461353b565b611b26565b61030e61078f3660046139a3565b611ccb565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c536600461353b565b611d95565b61030e6107d83660046139e0565b611e7e565b3480156107e957600080fd5b506102b76107f836600461353b565b611f70565b34801561080957600080fd5b506102b7610818366004613632565b611fe4565b34801561082957600080fd5b506102d9610838366004613aa1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b761088136600461353b565b6120c0565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613748565b612136565b6108c46121af565b816108ce816121fc565b600083815260086020526040902060028101546108ea90612251565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122c6565b6109478184612369565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612428565b6000828152600860205260409020600201546109cf90612251565b606060008054610a0a90613acf565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613acf565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612428565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612487565b505050565b610bd16121af565b81610bdb816121fc565b6000838152600860205260409020610bf2816124f5565b610bfc818461253f565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612627565b610c625760405162461bcd60e51b815260040161092b90613b09565b610bc48383836126a5565b610c756121af565b81610c7f816121fc565b6000838152600860205260409020610c979083612816565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce36121af565b80610ced816121fc565b6000828152600860205260409020610d04816124f5565b610d0d81612919565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129f9565b610d9a612a53565b565b6060816001600160401b03811115610db657610db6613844565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613844565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b56565b6020026020010181905250600060096000878785818110610e7b57610e7b613b56565b9050602002016020810190610e909190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b56565b60200260200101518281518110610ef357610ef3613b56565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612428565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b56565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612aa8565b612b0f565b9392505050565b6000610fce6121af565b346000610fdb8286612aa8565b9050610fe681612b40565b610ff08185612b8c565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b87565b60405180910390a295945050505050565b6110426121af565b60008060005b848110156110d95785858281811061106257611062613b56565b905060200201359250611074836121fc565b6000838152600860205260409020915061108d826124f5565b611097828561253f565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e96121af565b60008060005b838110156111705784848281811061110957611109613b56565b90506020020135925061111b836121fc565b6000838152600860205260409020915061113482612c2c565b61113d82612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f6121af565b80611189816121fc565b60008281526008602052604090206111a081612c2c565b6111a981612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613844565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613844565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b56565b60200260200101819052506000600a600087878581811061131857611318613b56565b905060200201602081019061132d9190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b56565b6020026020010151828151811061139057611390613b56565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129f9565b610d9a6000612cce565b60606000821180156114625750600b5461145f8385613bbf565b11155b61147e5760405162461bcd60e51b815260040161092b90613bd2565b816001600160401b0381111561149657611496613844565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b56565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b56565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129f9565b610d9a612d20565b600061159582612428565b60008281526008602052604090206115ac816124f5565b610fbd81612919565b606060018054610a0a90613acf565b6115cf338383612d63565b5050565b6115db6121af565b6000805b83811015611170578484828181106115f9576115f9613b56565b90506020020135915061160b826121fc565b60008281526008602052604090206116239084612816565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b6116726121af565b8161167c816121fc565b600083815260086020526040902061169381612c2c565b8054600b805460009190839081106116ad576116ad613b56565b90600052602060002090600302019050848160000154346116ce9190613bbf565b146116eb5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e31565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612627565b6117985760405162461bcd60e51b815260040161092b90613b09565b6117a484848484612e81565b50505050565b6117b26121af565b60008060005b848110156110d9578585828181106117d2576117d2613b56565b9050602002013592506117e4836121fc565b6000838152600860205260409020600281015490925061180390612251565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122c6565b61185b8285612369565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a16121af565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611aa9576000190187878281811061190557611905613b56565b905060200201359350611917846121fc565b60008481526008602052604090209250611930836124f5565b82546003840154600b805460a09290921b918390811061195257611952613b56565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bbf565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122c6565b611aa2565b6000196001860155611a5185888a612e31565b8989604051611a61929190613c29565b60408051918290038220898352602083018b9052917fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12910160405180910390a25b50506118e9565b5050505050505050565b6060611abe82612428565b6000611ad560408051602081019091526000815290565b90506000815111611af55760405180602001604052806000815250610fbd565b80611aff84612eb4565b604051602001611b10929190613c52565b6040516020818303038152906040529392505050565b611b2e6129f9565b81600003611b725760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bd15760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cd56121af565b600082118015611ced575034611ceb8387613c81565b145b611d095760405162461bcd60e51b815260040161092b90613bd2565b6000611d158686612aa8565b9050611d2081612b40565b600754600101915060005b83811015611d8a57611d3d8286612b8c565b611d478184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d7a93929190613b87565b60405180910390a2600101611d2b565b50505b949350505050565b611d9d6121af565b81611da7816121fc565b6000838152600860205260409020611dbe81612c2c565b8054600b80546000919083908110611dd857611dd8613b56565b9060005260206000209060030201905080600101548511611e0b5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e4c90849087612e31565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e886121af565b34825185611e969190613c81565b14611eb35760405162461bcd60e51b815260040161092b90613bd2565b6000611ebf8585612aa8565b9050611eca81612b40565b600754600101915060005b8351811015611f6757611f0182858381518110611ef457611ef4613b56565b6020026020010151612b8c565b611f0b8184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f3e57611f3e613b56565b60200260200101518888604051611f5793929190613b87565b60405180910390a2600101611ed5565b50509392505050565b611f786129f9565b43600b611f858484612aa8565b81548110611f9557611f95613b56565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cbf929190918252602082015260400190565b611fec6121af565b60008060005b838110156111705784848281811061200c5761200c613b56565b90506020020135925061201e836121fc565b60008381526008602052604090209150612037826124f5565b61204082612919565b156120845760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61208d826129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611ff2565b6120c86129f9565b600019600b6120d78484612aa8565b815481106120e7576120e7613b56565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cbf929190918252602082015260400190565b61213e6129f9565b6001600160a01b0381166121a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b6121ac81612cce565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b612205816111d9565b6001600160a01b0316336001600160a01b0316146121ac5760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361229d5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b60006122ab61ca8084613bbf565b90504381116122bd5750600092915050565b43900392915050565b60006122d1826111d9565b90506122e1816000846001612f46565b6122ea826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061238257612382613b56565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121ac5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124bc826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61255284612919565b8310156125945760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125c4600b84815481106125ac576125ac613b56565b90600052602060002090600302016000015485612aa8565b90506125cf81612b40565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612633836111d9565b9050806001600160a01b0316846001600160a01b0316148061267a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d8d5750836001600160a01b031661269384610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126b8826111d9565b6001600160a01b0316146126de5760405162461bcd60e51b815260040161092b90613c98565b6001600160a01b0382166127405760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61274d8383836001612f46565b826001600160a01b0316612760826111d9565b6001600160a01b0316146127865760405162461bcd60e51b815260040161092b90613c98565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61281f826124f5565b8154600383015460a01b6001600160a01b0319808416908216036128555760405162461bcd60e51b815260040161092b90613bfe565b6001840154600019146128ac576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128f2565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b6001810154600090600019810361296b5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061298457612984613b56565b906000526020600020906003020160010154826129a19190613bbf565b90504381116129b4575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a5b61300f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b055760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d8d565b600043600b8381548110612b2557612b25613b56565b90600052602060002090600302016002015411159050919050565b612b4981612b0f565b6121ac5760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061305f565b6001810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d286121af565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a8b3390565b816001600160a01b0316836001600160a01b031603612dc45760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e3d8383612aa8565b9050612e4881612b40565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e8c8484846126a5565b612e9884848484613079565b6117a45760405162461bcd60e51b815260040161092b90613cdd565b60606000612ec183613177565b60010190506000816001600160401b03811115612ee057612ee0613844565b6040519080825280601f01601f191660200182016040528015612f0a576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f1457509392505050565b80600114612f965760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fbe5750600082815260086020526040902060020154600019145b61300a5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061324f565b60006001600160a01b0384163b1561316f57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130bd903390899088908890600401613d2f565b6020604051808303816000875af19250505080156130f8575060408051601f3d908101601f191682019092526130f591810190613d6c565b60015b613155573d808015613126576040519150601f19603f3d011682016040523d82523d6000602084013e61312b565b606091505b50805160000361314d5760405162461bcd60e51b815260040161092b90613cdd565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d8d565b506001611d8d565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131b65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131e2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061320057662386f26fc10000830492506010015b6305f5e1008310613218576305f5e100830492506008015b612710831061322c57612710830492506004015b6064831061323e576064830492506002015b600a83106109cf5760010192915050565b6132598383613282565b6132666000848484613079565b610bc45760405162461bcd60e51b815260040161092b90613cdd565b6001600160a01b0382166132d85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561333d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b61334b600083836001612f46565b6000818152600260205260409020546001600160a01b0316156133b05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121ac57600080fd5b6000806040838503121561344357600080fd5b8235915060208301356134558161341b565b809150509250929050565b6001600160e01b0319811681146121ac57600080fd5b60006020828403121561348857600080fd5b8135610fbd81613460565b6000602082840312156134a557600080fd5b5035919050565b60005b838110156134c75781810151838201526020016134af565b50506000910152565b600081518084526134e88160208601602086016134ac565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134d0565b6000806040838503121561352257600080fd5b823561352d8161341b565b946020939093013593505050565b6000806040838503121561354e57600080fd5b50508035926020909101359150565b60008060006060848603121561357257600080fd5b833561357d8161341b565b9250602084013561358d8161341b565b929592945050506040919091013590565b80356001600160a01b0319811681146135b657600080fd5b919050565b600080604083850312156135ce57600080fd5b823591506135de6020840161359e565b90509250929050565b60008083601f8401126135f957600080fd5b5081356001600160401b0381111561361057600080fd5b6020830191508360208260051b850101111561362b57600080fd5b9250929050565b6000806020838503121561364557600080fd5b82356001600160401b0381111561365b57600080fd5b613667858286016135e7565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136ef57888603603f19018552825180518088529088019088880190845b818110156136d95783518352928a0192918a01916001016136bd565b509097505050938601939186019160010161369b565b509398975050505050505050565b60008060006040848603121561371257600080fd5b83356001600160401b0381111561372857600080fd5b613734868287016135e7565b909790965060209590950135949350505050565b60006020828403121561375a57600080fd5b8135610fbd8161341b565b602080825282518282018190526000919060409081850190868401855b828110156137b15781518051855286810151878601528501518585015260609093019290850190600101613782565b5091979650505050505050565b600080604083850312156137d157600080fd5b82356137dc8161341b565b91506020830135801515811461345557600080fd5b60008060006040848603121561380657600080fd5b83356001600160401b0381111561381c57600080fd5b613828868287016135e7565b909450925061383b90506020850161359e565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561388257613882613844565b604052919050565b600080600080608085870312156138a057600080fd5b84356138ab8161341b565b93506020858101356138bc8161341b565b93506040860135925060608601356001600160401b03808211156138df57600080fd5b818801915088601f8301126138f357600080fd5b81358181111561390557613905613844565b613917601f8201601f1916850161385a565b9150808252898482850101111561392d57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561396257600080fd5b83356001600160401b0381111561397857600080fd5b613984868287016135e7565b90945092505060208401356139988161341b565b809150509250925092565b600080600080608085870312156139b957600080fd5b84359350602085013592506139d06040860161359e565b9396929550929360600135925050565b6000806000606084860312156139f557600080fd5b83359250602080850135925060408501356001600160401b0380821115613a1b57600080fd5b818701915087601f830112613a2f57600080fd5b813581811115613a4157613a41613844565b8060051b9150613a5284830161385a565b818152918301840191848101908a841115613a6c57600080fd5b938501935b83851015613a9157613a828561359e565b82529385019390850190613a71565b8096505050505050509250925092565b60008060408385031215613ab457600080fd5b8235613abf8161341b565b915060208301356134558161341b565b600181811c90821680613ae357607f821691505b602082108103613b0357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b7e57600080fd5b610fbd8261359e565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613ba9565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b60006001600160fb1b03831115613c3f57600080fd5b8260051b80858437919091019392505050565b60008351613c648184602088016134ac565b835190830190613c788183602088016134ac565b01949350505050565b80820281158282048414176109cf576109cf613ba9565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d62908301846134d0565b9695505050505050565b600060208284031215613d7e57600080fd5b8151610fbd8161346056fea2646970667358221220f2bdba1caf01add5d9d0c859f09b34e6be24ec98d778f8a9cf110ac34053fb0664736f6c63430008130033` ) func TestLiquidStaking(t *testing.T) { - require := require.New(t) - - testReadContract := func(cfg config.Config, t *testing.T) { - ctx := context.Background() - - // Create a new blockchain - svr, err := itx.NewServer(cfg) - require.NoError(err) - require.NoError(svr.Start(ctx)) - defer func() { - require.NoError(svr.Stop(ctx)) - }() - - chainID := cfg.Chain.ID - bc := svr.ChainService(chainID).Blockchain() - sf := svr.ChainService(chainID).StateFactory() - ap := svr.ChainService(chainID).ActionPool() - dao := svr.ChainService(chainID).BlockDAO() - registry := svr.ChainService(chainID).Registry() - require.NotNil(bc) - require.NotNil(registry) - admin := identityset.PrivateKey(26) - state0 := hash.BytesToHash160(identityset.Address(26).Bytes()) - s := &state.Account{} - _, err = sf.State(s, protocol.LegacyKeyOption(state0)) - require.NoError(err) - require.Equal(unit.ConvertIotxToRau(100000000), s.Balance) - - // deploy staking contract - data, err := hex.DecodeString(_liquidStakingContractByteCode) - require.NoError(err) - fixedTime := time.Unix(cfg.Genesis.Timestamp, 0) - ex, err := action.SignedExecution(action.EmptyAddress, admin, 1, big.NewInt(0), 10000000, big.NewInt(testutil.TestGasPriceInt64), data) - require.NoError(err) - - deployHash, err := ex.Hash() - require.NoError(err) - require.NoError(ap.Add(context.Background(), ex)) - blk, err := bc.MintNewBlock(fixedTime) - require.NoError(err) - require.NoError(bc.CommitBlock(blk)) - r, err := dao.GetReceiptByActionHash(deployHash, 1) - require.NoError(err) - require.Equal(r.ContractAddress, "io123vqxxup8n3ld8jygvx729r6295pv9krjn2tjh") - - // set value - // contractABI, err := abi.JSON(strings.NewReader(blockindex.LiquidStakingContractABI)) - // require.NoError(err) - fixedAmount := unit.ConvertIotxToRau(200) - // sk := identityset.PrivateKey(26) - nonce := uint64(0) - // data, err = contractABI.Pack("addBucketType", big.NewInt(10), big.NewInt(10000)) - // require.NoError(err) - // require.True(len(data) > 0) - data, err = hex.DecodeString(`c8e7792300000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000002710`) - require.NoError(err) - ex, err = action.SignedExecution(r.ContractAddress, admin, nonce+2, fixedAmount, 10000000, big.NewInt(testutil.TestGasPriceInt64), data) - require.NoError(err) - require.NoError(ap.Add(context.Background(), ex)) - // data, err = contractABI.Pack("get") - // require.NoError(err) - // require.True(len(data) > 0) - // ex, err = action.SignedExecution(r.ContractAddress, sk, nonce+2, fixedAmount, 1000000, big.NewInt(testutil.TestGasPriceInt64), data) - // require.NoError(err) - // require.NoError(ap.Add(context.Background(), ex)) - blk, err = bc.MintNewBlock(fixedTime) - require.NoError(err) - require.NoError(bc.CommitBlock(blk)) - } - + r := require.New(t) + // prepare blockchain + ctx := context.Background() cfg := config.Default - testTriePath, err := testutil.PathOfTempFile("trie") - require.NoError(err) - testDBPath, err := testutil.PathOfTempFile("db") - require.NoError(err) - testIndexPath, err := testutil.PathOfTempFile("index") - require.NoError(err) - testBloomfilterIndexPath, err := testutil.PathOfTempFile("bloomfilterindex") - require.NoError(err) - testCandidateIndexPath, err := testutil.PathOfTempFile("candidateindex") - require.NoError(err) - testLiquidStakeIndexPath, err := testutil.PathOfTempFile("liquidstakeindex") - require.NoError(err) - testSystemLogPath, err := testutil.PathOfTempFile("systemlog") - require.NoError(err) - testConsensusPath, err := testutil.PathOfTempFile("consensus") - require.NoError(err) + cfg.Chain.ProducerPrivKey = identityset.PrivateKey(1).HexString() + cfg.Chain.EnableTrielessStateDB = false + cfg.Genesis.InitBalanceMap[identityset.Address(1).String()] = "1000000000000000000000000000" + + bc, sf, dao, ap, indexer := prepareliquidStakingBlockchain(ctx, cfg, r) defer func() { - testutil.CleanupPath(testTriePath) - testutil.CleanupPath(testDBPath) - testutil.CleanupPath(testIndexPath) - testutil.CleanupPath(testBloomfilterIndexPath) - testutil.CleanupPath(testCandidateIndexPath) - testutil.CleanupPath(testLiquidStakeIndexPath) - testutil.CleanupPath(testSystemLogPath) - testutil.CleanupPath(testConsensusPath) - // clear the gateway - delete(cfg.Plugins, config.GatewayPlugin) + r.NoError(bc.Stop(ctx)) }() + ctx = genesis.WithGenesisContext(context.Background(), bc.Genesis()) - cfg.ActPool.MinGasPriceStr = "0" - cfg.Chain.TrieDBPatchFile = "" - cfg.Chain.TrieDBPath = testTriePath - cfg.Chain.ChainDBPath = testDBPath - cfg.Chain.IndexDBPath = testIndexPath - cfg.Chain.BloomfilterIndexDBPath = testBloomfilterIndexPath - cfg.Chain.CandidateIndexDBPath = testCandidateIndexPath - cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexPath - cfg.System.SystemLogDBPath = testSystemLogPath - cfg.Consensus.RollDPoS.ConsensusDBPath = testConsensusPath - cfg.Chain.ProducerPrivKey = "a000000000000000000000000000000000000000000000000000000000000000" - cfg.Consensus.Scheme = config.RollDPoSScheme - cfg.Genesis.NumDelegates = 1 - cfg.Genesis.NumSubEpochs = 10 - cfg.Genesis.Delegates = []genesis.Delegate{ - { - OperatorAddrStr: identityset.Address(0).String(), - RewardAddrStr: identityset.Address(0).String(), - VotesStr: "10", - }, + // deploy smart contract + deployAddr := blockindex.LiquidStakingContractAddress + param := callParam{ + contractAddr: deployAddr, + bytecode: _liquidStakingContractByteCode, + amount: big.NewInt(0), + gasLimit: 20000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), } - cfg.Genesis.PollMode = "lifeLong" - cfg.Genesis.EnableGravityChainVoting = false - cfg.Genesis.ActionGasLimit = 100000000 + contractAddresses := deployContracts(bc, sf, dao, ap, ¶m, r) + + // add bucket type, amount=10, duration=100 + lsdABI, err := abi.JSON(strings.NewReader(blockindex.LiquidStakingContractABI)) + r.NoError(err) + data, err := lsdABI.Pack("addBucketType", big.NewInt(10), big.NewInt(100)) + r.NoError(err) + addBucketTypeParam := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + // add bucket to candidate + delegate := [12]byte{} + copy(delegate[:], []byte("delegate1")) + data, err = lsdABI.Pack("stake", big.NewInt(100), delegate) + r.NoError(err) + addBucketParam := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(10), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, blk := writeContract(bc, sf, dao, ap, []*callParam{&addBucketTypeParam, &addBucketParam}, r) + r.Len(receipts, 2) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[1].Status) + + buckets, err := indexer.GetBuckets() + r.NoError(err) + r.Equal(1, len(buckets)) + r.True(buckets[0].AutoStake) + r.Equal("delegate1", buckets[0].Candidate) + r.EqualValues(identityset.PrivateKey(1).PublicKey().Address().String(), buckets[0].Owner.String()) + r.EqualValues(0, buckets[0].StakedAmount.Cmp(big.NewInt(10))) + r.EqualValues(100*cfg.Genesis.BlockInterval, buckets[0].StakedDuration) + r.EqualValues(blk.Timestamp().UTC(), buckets[0].CreateTime) + r.EqualValues(blk.Timestamp().UTC(), buckets[0].StakeStartTime) + r.EqualValues(time.Unix(0, 0).UTC(), buckets[0].UnstakeStartTime) + r.EqualValues(1, buckets[0].Index) +} + +func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.LiquidStakingIndexer) { + defer func() { + delete(cfg.Plugins, config.GatewayPlugin) + }() cfg.Plugins[config.GatewayPlugin] = true cfg.Chain.EnableAsyncIndexWrite = false - cfg.Genesis.AleutianBlockHeight = 0 - cfg.Genesis.BeringBlockHeight = 0 + cfg.Genesis.EnableGravityChainVoting = false + testTriePath, err := testutil.PathOfTempFile("trie") + r.NoError(err) + defer testutil.CleanupPath(testTriePath) + testLiquidStakeIndexerPath, err := testutil.PathOfTempFile("liquidstakeindexer") + r.NoError(err) + defer testutil.CleanupPath(testLiquidStakeIndexerPath) + + cfg.Chain.TrieDBPath = testTriePath + cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexerPath + cfg.ActPool.MinGasPriceStr = "0" + + cfg.Genesis.Blockchain.AleutianBlockHeight = 0 + cfg.Genesis.Blockchain.BeringBlockHeight = 0 + cfg.Genesis.HawaiiBlockHeight = 0 - t.Run("test read staking contract", func(t *testing.T) { - testReadContract(cfg, t) - }) + cfg.Genesis.CookBlockHeight = 0 + cfg.Genesis.DardanellesBlockHeight = 0 + cfg.Genesis.DaytonaBlockHeight = 0 + cfg.Genesis.EasterBlockHeight = 0 + cfg.Genesis.FbkMigrationBlockHeight = 0 + cfg.Genesis.FairbankBlockHeight = 0 + cfg.Genesis.GreenlandBlockHeight = 0 + cfg.Genesis.IcelandBlockHeight = 0 + + // London is enabled at okhotsk height + cfg.Genesis.Blockchain.JutlandBlockHeight = 0 + cfg.Genesis.Blockchain.KamchatkaBlockHeight = 0 + cfg.Genesis.Blockchain.LordHoweBlockHeight = 0 + cfg.Genesis.Blockchain.MidwayBlockHeight = 0 + cfg.Genesis.Blockchain.NewfoundlandBlockHeight = 0 + cfg.Genesis.Blockchain.OkhotskBlockHeight = 0 + + registry := protocol.NewRegistry() + acc := account.NewProtocol(rewarding.DepositGas) + r.NoError(acc.Register(registry)) + rp := rolldpos.NewProtocol(cfg.Genesis.NumCandidateDelegates, cfg.Genesis.NumDelegates, cfg.Genesis.NumSubEpochs) + r.NoError(rp.Register(registry)) + // create state factory + var sf factory.Factory + var daoKV db.KVStore + + factoryCfg := factory.GenerateConfig(cfg.Chain, cfg.Genesis) + if cfg.Chain.EnableTrielessStateDB { + if cfg.Chain.EnableStateDBCaching { + daoKV, err = db.CreateKVStoreWithCache(cfg.DB, cfg.Chain.TrieDBPath, cfg.Chain.StateDBCacheSize) + } else { + daoKV, err = db.CreateKVStore(cfg.DB, cfg.Chain.TrieDBPath) + } + r.NoError(err) + sf, err = factory.NewStateDB(factoryCfg, daoKV, factory.RegistryStateDBOption(registry)) + } else { + sf, err = factory.NewFactory(factoryCfg, db.NewMemKVStore(), factory.RegistryOption(registry)) + } + r.NoError(err) + ap, err := actpool.NewActPool(cfg.Genesis, sf, cfg.ActPool) + r.NoError(err) + // create indexer + indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.Genesis.Hash()) + r.NoError(err) + cc := cfg.DB + cc.DbPath = testLiquidStakeIndexerPath + liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) + // create BlockDAO + dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) + r.NotNil(dao) + bc := blockchain.NewBlockchain( + cfg.Chain, + cfg.Genesis, + dao, + factory.NewMinter(sf, ap), + blockchain.BlockValidatorOption(block.NewValidator( + sf, + protocol.NewGenericValidator(sf, accountutil.AccountState), + )), + ) + reward := rewarding.NewProtocol(cfg.Genesis.Rewarding) + r.NoError(reward.Register(registry)) + + r.NotNil(bc) + execution := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGas) + r.NoError(execution.Register(registry)) + r.NoError(bc.Start(ctx)) + + return bc, sf, dao, ap, liquidStakeIndexer +} + +func deployContracts( + bc blockchain.Blockchain, + sf factory.Factory, + dao blockdao.BlockDAO, + ap actpool.ActPool, + param *callParam, + r *require.Assertions, +) (contractAddresses string) { + sk := param.sk + bytecode, err := hex.DecodeString(param.bytecode) + r.NoError(err) + state, err := accountutil.AccountState(genesis.WithGenesisContext(context.Background(), bc.Genesis()), sf, sk.PublicKey().Address()) + r.NoError(err) + nonce := state.PendingNonce() + amount := param.amount + gasLimit := param.gasLimit + gasPrice := param.gasPrice + exec, err := action.NewExecutionWithAccessList(action.EmptyAddress, nonce, amount, gasLimit, gasPrice, bytecode, nil) + r.NoError(err) + builder := &action.EnvelopeBuilder{} + elp := builder.SetAction(exec). + SetNonce(exec.Nonce()). + SetGasLimit(gasLimit). + SetGasPrice(gasPrice). + Build() + selp, err := action.Sign(elp, sk) + r.NoError(err) + err = ap.Add(context.Background(), selp) + r.NoError(err) + selpHash, err := selp.Hash() + + blk, err := bc.MintNewBlock(testutil.TimestampNow()) + r.NoError(err) + err = bc.CommitBlock(blk) + r.NoError(err) + + receipt, err := dao.GetReceiptByActionHash(selpHash, blk.Height()) + r.NoError(err) + r.NotNil(receipt) + r.Equal(uint64(iotextypes.ReceiptStatus_Success), receipt.Status) + + return receipt.ContractAddress +} + +type callParam struct { + contractAddr string + bytecode string + amount *big.Int + gasLimit uint64 + gasPrice *big.Int + sk crypto.PrivateKey +} + +func writeContract(bc blockchain.Blockchain, + sf factory.Factory, + dao blockdao.BlockDAO, + ap actpool.ActPool, + params []*callParam, + r *require.Assertions, +) ([]*action.Receipt, *block.Block) { + nonces := map[string]uint64{} + hashes := []hash.Hash256{} + for _, param := range params { + nonce := uint64(1) + var ok bool + sk := param.sk + executor := sk.PublicKey().Address() + if nonce, ok = nonces[executor.String()]; !ok { + state, err := accountutil.AccountState(genesis.WithGenesisContext(context.Background(), bc.Genesis()), sf, executor) + r.NoError(err) + nonce = state.PendingNonce() + } else { + nonce++ + } + nonces[executor.String()] = nonce + + amount := param.amount + gasLimit := param.gasLimit + gasPrice := param.gasPrice + bytecode, err := hex.DecodeString(param.bytecode) + r.NoError(err) + exec, err := action.NewExecutionWithAccessList(param.contractAddr, nonce, amount, gasLimit, gasPrice, bytecode, nil) + r.NoError(err) + builder := &action.EnvelopeBuilder{} + elp := builder.SetAction(exec). + SetNonce(exec.Nonce()). + SetGasLimit(gasLimit). + SetGasPrice(gasPrice). + Build() + selp, err := action.Sign(elp, sk) + r.NoError(err) + err = ap.Add(context.Background(), selp) + r.NoError(err) + selpHash, err := selp.Hash() + hashes = append(hashes, selpHash) + } + + blk, err := bc.MintNewBlock(testutil.TimestampNow()) + r.NoError(err) + err = bc.CommitBlock(blk) + r.NoError(err) + + receipts := []*action.Receipt{} + for _, hash := range hashes { + receipt, err := dao.GetReceiptByActionHash(hash, blk.Height()) + r.NoError(err) + receipts = append(receipts, receipt) + } + return receipts, blk } diff --git a/e2etest/staking_test.go b/e2etest/staking_test.go index 98075e9296..f4774ed19e 100644 --- a/e2etest/staking_test.go +++ b/e2etest/staking_test.go @@ -33,6 +33,11 @@ import ( "github.com/iotexproject/iotex-core/testutil" ) +func TestAAA(t *testing.T) { + t.Log(identityset.Address(1)) + t.Log(identityset.PrivateKey(1).HexString()) +} + func TestStakingContract(t *testing.T) { require := require.New(t) From c3fe925827666c88594042cf556f26bcbc81f179 Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 26 Apr 2023 22:59:51 +0800 Subject: [PATCH 14/51] use indexed event field --- blockindex/liquidstaking_indexer.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index a4b043cef6..9707fee71b 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -1564,7 +1564,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp tim } func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1592,7 +1592,7 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { } func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp time.Time) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1607,7 +1607,7 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t } func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp time.Time) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1654,7 +1654,7 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1681,7 +1681,7 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err } func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1708,7 +1708,7 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro } func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } @@ -1727,7 +1727,7 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro } func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { - tokenIDParam, err := event.fieldUint256("tokenId") + tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } From 0491059931e1fc1d6f8ff554f3bba09e669d5024 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 27 Apr 2023 20:25:16 +0800 Subject: [PATCH 15/51] add test --- blockindex/liquidstaking_data.go | 9 +- blockindex/liquidstaking_indexer.go | 83 ++++--- e2etest/liquid_staking_test.go | 363 ++++++++++++++++++++++++---- 3 files changed, 384 insertions(+), 71 deletions(-) diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go index 970d6c9905..adaa391e8d 100644 --- a/blockindex/liquidstaking_data.go +++ b/blockindex/liquidstaking_data.go @@ -13,7 +13,7 @@ type ( liquidStakingCache struct { idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket - idBucketTypeMap map[uint64]*BucketType + idBucketTypeMap map[uint64]*BucketType // map[token]BucketType propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index height uint64 } @@ -100,7 +100,7 @@ func (s *liquidStakingCache) deleteBucketInfo(id uint64) { if !ok { return } - s.idBucketTypeMap[id] = nil + s.idBucketMap[id] = nil if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { return } @@ -146,6 +146,9 @@ func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { if !ok { continue } + if bi.UnstakedAt != nil { + continue + } bt := s.mustGetBucketType(bi.TypeIndex) votes.Add(votes, bt.Amount) } @@ -267,7 +270,7 @@ func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { func (s *liquidStakingIndexer) burnBucket(id uint64) { s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") - s.dirtyCache.putBucketInfo(id, nil) + s.dirtyCache.deleteBucketInfo(id) } func (s *liquidStakingIndexer) commit() error { diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 9707fee71b..8217464981 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -1278,6 +1278,7 @@ type ( GetCandidateVotes(candidate string) *big.Int GetBuckets() ([]*Bucket, error) + GetBucket(id uint64) (*Bucket, error) } liquidStakingIndexer struct { @@ -1329,7 +1330,8 @@ var ( errInvlidEventParam = errors.New("invalid event param") errBucketTypeNotExist = errors.New("bucket type does not exist") - errBucketInfoNotExist = errors.New("bucket info does not exist") + // ErrBucketInfoNotExist is the error when bucket does not exist + ErrBucketInfoNotExist = errors.New("bucket info does not exist") ) func init() { @@ -1422,6 +1424,19 @@ func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { return vbs, nil } +func (s *liquidStakingIndexer) GetBucket(id uint64) (*Bucket, error) { + bi, ok := s.cleanCache.idBucketMap[id] + if !ok { + return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) + } + bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) + vb, err := convertToVoteBucket(id, bi, bt) + if err != nil { + return nil, err + } + return vb, nil +} + func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) @@ -1550,12 +1565,10 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp tim if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - tail := len(delegateParam) - 1 - for ; tail >= 0 && delegateParam[tail] == 0; tail-- { - } + bucket := BucketInfo{ TypeIndex: btIdx, - Delegate: string(delegateParam[:tail+1]), + Delegate: delegateParam, Owner: s.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } @@ -1575,7 +1588,7 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } bt, ok := s.getBucketType(b.TypeIndex) if !ok { @@ -1599,7 +1612,7 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnlockedAt = ×tamp s.putBucketInfo(tokenIDParam.Uint64(), b) @@ -1614,7 +1627,7 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp t b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnstakedAt = ×tamp s.putBucketInfo(tokenIDParam.Uint64(), b) @@ -1642,7 +1655,7 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } b, ok := s.getBucketInfo(tokenIDsParam[0].Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx b.UnlockedAt = nil @@ -1665,7 +1678,7 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } bt, ok := s.getBucketType(b.TypeIndex) if !ok { @@ -1692,7 +1705,7 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } bt, ok := s.getBucketType(b.TypeIndex) if !ok { @@ -1719,7 +1732,7 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro b, ok := s.getBucketInfo(tokenIDParam.Uint64()) if !ok { - return errors.Wrapf(errBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.Delegate = string(delegateParam[:]) s.putBucketInfo(tokenIDParam.Uint64(), b) @@ -1752,8 +1765,16 @@ func (e eventParam) fieldUint256(name string) (*big.Int, error) { return eventField[*big.Int](e, name) } -func (e eventParam) fieldBytes12(name string) ([12]byte, error) { - return eventField[[12]byte](e, name) +func (e eventParam) fieldBytes12(name string) (string, error) { + data, err := eventField[[12]byte](e, name) + if err != nil { + return "", err + } + // remove trailing zeros + tail := len(data) - 1 + for ; tail >= 0 && data[tail] == 0; tail-- { + } + return string(data[:tail+1]), nil } func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { @@ -1765,19 +1786,11 @@ func (e eventParam) fieldAddress(name string) (common.Address, error) { } func (e eventParam) indexedFieldAddress(name string) (common.Address, error) { - bytes, err := eventField[hash.Hash256](e, name) - if err != nil { - return common.Address{}, err - } - return common.BytesToAddress(bytes[:]), nil + return eventField[common.Address](e, name) } func (e eventParam) indexedFieldUint256(name string) (*big.Int, error) { - bytes, err := eventField[hash.Hash256](e, name) - if err != nil { - return nil, err - } - return big.NewInt(0).SetBytes(bytes[:]), nil + return eventField[*big.Int](e, name) } func (bt *BucketType) toProto() *indexpb.BucketType { @@ -1905,12 +1918,28 @@ func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) } } // unpack indexed fields - i := 0 + // i := 0 + // for _, arg := range abiEvent.Inputs { + // if arg.Indexed { + // i++ + // event[arg.Name] = log.Topics[i] + // } + // } + args := make(abi.Arguments, 0) for _, arg := range abiEvent.Inputs { if arg.Indexed { - i++ - event[arg.Name] = log.Topics[i] + args = append(args, arg) + } + } + topics := make([]common.Hash, 0) + for i, topic := range log.Topics { + if i > 0 { + topics = append(topics, common.Hash(topic)) } } + err := abi.ParseTopicsIntoMap(event, args, topics) + if err != nil { + return nil, errors.Wrap(err, "unpack event indexed fields failed") + } return event, nil } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 3319631eb5..fb6153ccec 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-core/action" @@ -63,50 +64,299 @@ func TestLiquidStaking(t *testing.T) { sk: identityset.PrivateKey(1), } contractAddresses := deployContracts(bc, sf, dao, ap, ¶m, r) - - // add bucket type, amount=10, duration=100 lsdABI, err := abi.JSON(strings.NewReader(blockindex.LiquidStakingContractABI)) r.NoError(err) - data, err := lsdABI.Pack("addBucketType", big.NewInt(10), big.NewInt(100)) - r.NoError(err) - addBucketTypeParam := callParam{ - contractAddr: contractAddresses, - bytecode: hex.EncodeToString(data), - amount: big.NewInt(0), - gasLimit: 1000000, - gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + + // init bucket type + bucketTypes := []struct { + amount int64 + duration int64 + }{ + {10, 100}, + {10, 10}, + {100, 100}, + {100, 10}, } - // add bucket to candidate - delegate := [12]byte{} - copy(delegate[:], []byte("delegate1")) - data, err = lsdABI.Pack("stake", big.NewInt(100), delegate) - r.NoError(err) - addBucketParam := callParam{ - contractAddr: contractAddresses, - bytecode: hex.EncodeToString(data), - amount: big.NewInt(10), - gasLimit: 1000000, - gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + params := []*callParam{} + for i := range bucketTypes { + data, err := lsdABI.Pack("addBucketType", big.NewInt(bucketTypes[i].amount), big.NewInt(bucketTypes[i].duration)) + r.NoError(err) + param := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + params = append(params, ¶m) + } + receipts, _ := writeContract(bc, sf, dao, ap, params, r) + r.Len(receipts, len(params)) + for _, receipt := range receipts { + r.EqualValues(iotextypes.ReceiptStatus_Success, receipt.Status) } - receipts, blk := writeContract(bc, sf, dao, ap, []*callParam{&addBucketTypeParam, &addBucketParam}, r) - r.Len(receipts, 2) - r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[1].Status) - buckets, err := indexer.GetBuckets() - r.NoError(err) - r.Equal(1, len(buckets)) - r.True(buckets[0].AutoStake) - r.Equal("delegate1", buckets[0].Candidate) - r.EqualValues(identityset.PrivateKey(1).PublicKey().Address().String(), buckets[0].Owner.String()) - r.EqualValues(0, buckets[0].StakedAmount.Cmp(big.NewInt(10))) - r.EqualValues(100*cfg.Genesis.BlockInterval, buckets[0].StakedDuration) - r.EqualValues(blk.Timestamp().UTC(), buckets[0].CreateTime) - r.EqualValues(blk.Timestamp().UTC(), buckets[0].StakeStartTime) - r.EqualValues(time.Unix(0, 0).UTC(), buckets[0].UnstakeStartTime) - r.EqualValues(1, buckets[0].Index) + simpleStake := func(candName string, amount, duration *big.Int) *blockindex.Bucket { + return stake(lsdABI, bc, sf, dao, ap, contractAddresses, indexer, r, candName, amount, duration) + } + + t.Run("stake", func(t *testing.T) { + delegate := [12]byte{} + copy(delegate[:], []byte("delegate2")) + data, err := lsdABI.Pack("stake", big.NewInt(10), delegate) + r.NoError(err) + param := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(10), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, blk := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + buckets, err := indexer.GetBuckets() + r.NoError(err) + bt := buckets[len(buckets)-1] + tokenID := bt.Index + r.EqualValues(1, bt.Index) + r.True(bt.AutoStake) + r.Equal("delegate2", bt.Candidate) + r.EqualValues(identityset.PrivateKey(1).PublicKey().Address().String(), bt.Owner.String()) + r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) + r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) + r.EqualValues(blk.Timestamp().UTC(), bt.CreateTime) + r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) + r.EqualValues(time.Unix(0, 0).UTC(), bt.UnstakeStartTime) + r.EqualValues(10, indexer.GetCandidateVotes("delegate2").Int64()) + + t.Run("unlock", func(t *testing.T) { + data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, blk = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err := indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) + r.EqualValues(10, indexer.GetCandidateVotes("delegate2").Int64()) + + t.Run("unstake", func(t *testing.T) { + jumpBlocks(bc, 10, r) + data, err = lsdABI.Pack("unstake", big.NewInt(int64(bt.Index))) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, blk = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err := indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.EqualValues(blk.Timestamp().UTC(), bt.UnstakeStartTime) + r.EqualValues(0, indexer.GetCandidateVotes("delegate2").Int64()) + + t.Run("withdraw", func(t *testing.T) { + // jumpBlocks(bc, 3*24*3600/5, r) + tokenID := bt.Index + + addr := common.BytesToAddress(identityset.PrivateKey(1).PublicKey().Bytes()) + data, err := lsdABI.Pack("withdraw", big.NewInt(int64(tokenID)), addr) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) + }) + }) + }) + }) + + t.Run("lock & unlock", func(t *testing.T) { + bt := simpleStake("delegate3", big.NewInt(10), big.NewInt(10)) + tokenID := bt.Index + + data, err := lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + + data, err = lsdABI.Pack("lock", big.NewInt(int64(bt.Index)), big.NewInt(10)) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.True(bt.AutoStake) + }) + t.Run("merge", func(t *testing.T) { + // stake 10 bucket + candName := "delegate3" + params := []*callParam{} + for i := 0; i < 10; i++ { + delegate := [12]byte{} + copy(delegate[:], []byte(candName)) + data, err := lsdABI.Pack("stake", big.NewInt(10), delegate) + r.NoError(err) + param := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(10), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + params = append(params, ¶m) + } + receipts, _ := writeContract(bc, sf, dao, ap, params, r) + r.Len(receipts, len(params)) + for _, receipt := range receipts { + r.EqualValues(iotextypes.ReceiptStatus_Success, receipt.Status) + } + buckets, err := indexer.GetBuckets() + r.NoError(err) + r.True(len(buckets) >= 10) + // merge + newBuckets := buckets[len(buckets)-10:] + tokens := []*big.Int{} + for _, bucket := range newBuckets { + tokens = append(tokens, big.NewInt(int64(bucket.Index))) + } + data, err := lsdABI.Pack("merge", tokens, big.NewInt(100)) + r.NoError(err) + param := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + }) + + t.Run("extend duration", func(t *testing.T) { + // stake + bt := simpleStake("delegate3", big.NewInt(10), big.NewInt(10)) + tokenID := bt.Index + r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) + // extend duration + data, err := lsdABI.Pack("extendDuration", big.NewInt(int64(tokenID)), big.NewInt(100)) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) + }) + + t.Run("increase amount", func(t *testing.T) { + bt := simpleStake("delegate4", big.NewInt(10), big.NewInt(10)) + tokenID := bt.Index + + data, err := lsdABI.Pack("increaseAmount", big.NewInt(int64(tokenID)), big.NewInt(100)) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(90), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.EqualValues(100, bt.StakedAmount.Int64()) + }) + + t.Run("change delegate", func(t *testing.T) { + bt := simpleStake("delegate5", big.NewInt(10), big.NewInt(10)) + tokenID := bt.Index + r.EqualValues("delegate5", bt.Candidate) + + delegate := [12]byte{} + copy(delegate[:], []byte("delegate6")) + data, err := lsdABI.Pack("changeDelegate", big.NewInt(int64(tokenID)), delegate) + r.NoError(err) + param = callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: big.NewInt(0), + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.NoError(err) + r.EqualValues("delegate6", bt.Candidate) + }) + } func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.LiquidStakingIndexer) { @@ -192,8 +442,8 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r protocol.NewGenericValidator(sf, accountutil.AccountState), )), ) - reward := rewarding.NewProtocol(cfg.Genesis.Rewarding) - r.NoError(reward.Register(registry)) + // reward := rewarding.NewProtocol(cfg.Genesis.Rewarding) + // r.NoError(reward.Register(registry)) r.NotNil(bc) execution := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGas) @@ -313,3 +563,34 @@ func writeContract(bc blockchain.Blockchain, } return receipts, blk } + +func jumpBlocks(bc blockchain.Blockchain, count int, r *require.Assertions) { + for i := 0; i < count; i++ { + blk, err := bc.MintNewBlock(testutil.TimestampNow()) + r.NoError(err) + err = bc.CommitBlock(blk) + r.NoError(err) + } +} + +func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blockdao.BlockDAO, ap actpool.ActPool, contractAddresses string, indexer blockindex.LiquidStakingIndexer, r *require.Assertions, candName string, amount, duration *big.Int) *blockindex.Bucket { + delegate := [12]byte{} + copy(delegate[:], []byte(candName)) + data, err := lsdABI.Pack("stake", duration, delegate) + r.NoError(err) + param := callParam{ + contractAddr: contractAddresses, + bytecode: hex.EncodeToString(data), + amount: amount, + gasLimit: 1000000, + gasPrice: big.NewInt(0), + sk: identityset.PrivateKey(1), + } + receipts, _ := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) + r.Len(receipts, 1) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + buckets, err := indexer.GetBuckets() + r.NoError(err) + bt := buckets[len(buckets)-1] + return bt +} From 2eb8ce1c7a841f9d18f7c469043c673a6041d9fc Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 27 Apr 2023 21:33:17 +0800 Subject: [PATCH 16/51] refactor --- action/protocol/execution/protocol_test.go | 9 +- blockchain/config.go | 66 +++-- blockindex/liquidstaking_data.go | 287 --------------------- blockindex/liquidstaking_indexer.go | 284 +++++++++++++++++++- blockindex/liquidstaking_indexer_test.go | 12 - chainservice/builder.go | 14 +- chainservice/chainservice.go | 13 +- e2etest/liquid_staking_test.go | 1 - e2etest/staking_test.go | 5 - go.mod | 2 +- 10 files changed, 318 insertions(+), 375 deletions(-) delete mode 100644 blockindex/liquidstaking_data.go delete mode 100644 blockindex/liquidstaking_indexer_test.go diff --git a/action/protocol/execution/protocol_test.go b/action/protocol/execution/protocol_test.go index e0b31cd420..5026ab062a 100644 --- a/action/protocol/execution/protocol_test.go +++ b/action/protocol/execution/protocol_test.go @@ -381,12 +381,8 @@ func (sct *SmartContractTest) prepareBlockchain( testTriePath, err := testutil.PathOfTempFile("trie") r.NoError(err) defer testutil.CleanupPath(testTriePath) - testLiquidStakeIndexerPath, err := testutil.PathOfTempFile("liquidstakeindexer") - r.NoError(err) - defer testutil.CleanupPath(testLiquidStakeIndexerPath) cfg.Chain.TrieDBPath = testTriePath - cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexerPath cfg.ActPool.MinGasPriceStr = "0" if sct.InitGenesis.IsBering { cfg.Genesis.Blockchain.AleutianBlockHeight = 0 @@ -442,11 +438,8 @@ func (sct *SmartContractTest) prepareBlockchain( // create indexer indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.Genesis.Hash()) r.NoError(err) - cc := cfg.DB - cc.DbPath = testLiquidStakeIndexerPath - liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) // create BlockDAO - dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) + dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer}) r.NotNil(dao) bc := blockchain.NewBlockchain( cfg.Chain, diff --git a/blockchain/config.go b/blockchain/config.go index 042e03dcff..cabaeb2252 100644 --- a/blockchain/config.go +++ b/blockchain/config.go @@ -24,24 +24,23 @@ import ( type ( // Config is the config struct for blockchain package Config struct { - ChainDBPath string `yaml:"chainDBPath"` - TrieDBPatchFile string `yaml:"trieDBPatchFile"` - TrieDBPath string `yaml:"trieDBPath"` - StakingPatchDir string `yaml:"stakingPatchDir"` - IndexDBPath string `yaml:"indexDBPath"` - BloomfilterIndexDBPath string `yaml:"bloomfilterIndexDBPath"` - CandidateIndexDBPath string `yaml:"candidateIndexDBPath"` - StakingIndexDBPath string `yaml:"stakingIndexDBPath"` - LiquidStakingIndexDBPath string `yaml:"liquidStakingIndexDBPath"` - ID uint32 `yaml:"id"` - EVMNetworkID uint32 `yaml:"evmNetworkID"` - Address string `yaml:"address"` - ProducerPrivKey string `yaml:"producerPrivKey"` - ProducerPrivKeySchema string `yaml:"producerPrivKeySchema"` - SignatureScheme []string `yaml:"signatureScheme"` - EmptyGenesis bool `yaml:"emptyGenesis"` - GravityChainDB db.Config `yaml:"gravityChainDB"` - Committee committee.Config `yaml:"committee"` + ChainDBPath string `yaml:"chainDBPath"` + TrieDBPatchFile string `yaml:"trieDBPatchFile"` + TrieDBPath string `yaml:"trieDBPath"` + StakingPatchDir string `yaml:"stakingPatchDir"` + IndexDBPath string `yaml:"indexDBPath"` + BloomfilterIndexDBPath string `yaml:"bloomfilterIndexDBPath"` + CandidateIndexDBPath string `yaml:"candidateIndexDBPath"` + StakingIndexDBPath string `yaml:"stakingIndexDBPath"` + ID uint32 `yaml:"id"` + EVMNetworkID uint32 `yaml:"evmNetworkID"` + Address string `yaml:"address"` + ProducerPrivKey string `yaml:"producerPrivKey"` + ProducerPrivKeySchema string `yaml:"producerPrivKeySchema"` + SignatureScheme []string `yaml:"signatureScheme"` + EmptyGenesis bool `yaml:"emptyGenesis"` + GravityChainDB db.Config `yaml:"gravityChainDB"` + Committee committee.Config `yaml:"committee"` EnableTrielessStateDB bool `yaml:"enableTrielessStateDB"` // EnableStateDBCaching enables cachedStateDBOption @@ -76,22 +75,21 @@ type ( var ( // DefaultConfig is the default config of chain DefaultConfig = Config{ - ChainDBPath: "/var/data/chain.db", - TrieDBPatchFile: "/var/data/trie.db.patch", - TrieDBPath: "/var/data/trie.db", - StakingPatchDir: "/var/data", - IndexDBPath: "/var/data/index.db", - BloomfilterIndexDBPath: "/var/data/bloomfilter.index.db", - CandidateIndexDBPath: "/var/data/candidate.index.db", - StakingIndexDBPath: "/var/data/staking.index.db", - LiquidStakingIndexDBPath: "/var/data/liquidstaking.index.db", - ID: 1, - EVMNetworkID: 4689, - Address: "", - ProducerPrivKey: generateRandomKey(SigP256k1), - SignatureScheme: []string{SigP256k1}, - EmptyGenesis: false, - GravityChainDB: db.Config{DbPath: "/var/data/poll.db", NumRetries: 10}, + ChainDBPath: "/var/data/chain.db", + TrieDBPatchFile: "/var/data/trie.db.patch", + TrieDBPath: "/var/data/trie.db", + StakingPatchDir: "/var/data", + IndexDBPath: "/var/data/index.db", + BloomfilterIndexDBPath: "/var/data/bloomfilter.index.db", + CandidateIndexDBPath: "/var/data/candidate.index.db", + StakingIndexDBPath: "/var/data/staking.index.db", + ID: 1, + EVMNetworkID: 4689, + Address: "", + ProducerPrivKey: generateRandomKey(SigP256k1), + SignatureScheme: []string{SigP256k1}, + EmptyGenesis: false, + GravityChainDB: db.Config{DbPath: "/var/data/poll.db", NumRetries: 10}, Committee: committee.Config{ GravityChainAPIs: []string{}, }, diff --git a/blockindex/liquidstaking_data.go b/blockindex/liquidstaking_data.go deleted file mode 100644 index adaa391e8d..0000000000 --- a/blockindex/liquidstaking_data.go +++ /dev/null @@ -1,287 +0,0 @@ -package blockindex - -import ( - "math/big" - "time" - - "github.com/iotexproject/iotex-core/db" - "github.com/iotexproject/iotex-core/db/batch" - "github.com/pkg/errors" -) - -type ( - liquidStakingCache struct { - idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo - candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket - idBucketTypeMap map[uint64]*BucketType // map[token]BucketType - propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index - height uint64 - } - - liquidStakingData struct { - dirty batch.CachedBatch // im-memory dirty data - dirtyCache *liquidStakingCache - clean db.KVStore // clean data in db - cleanCache *liquidStakingCache // in-memory index for clean data - } -) - -func newLiquidStakingCache() *liquidStakingCache { - return &liquidStakingCache{ - idBucketMap: make(map[uint64]*BucketInfo), - idBucketTypeMap: make(map[uint64]*BucketType), - propertyBucketTypeMap: make(map[int64]map[int64]uint64), - candidateBucketMap: make(map[string]map[uint64]bool), - } -} - -func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { - for i := 0; i < b.Size(); i++ { - write, err := b.Entry(i) - if err != nil { - return err - } - switch write.Namespace() { - case _liquidStakingBucketInfoNS: - if write.WriteType() == batch.Put { - var bi BucketInfo - if err = bi.deserialize(write.Value()); err != nil { - return err - } - id := deserializeUint64(write.Key()) - s.putBucketInfo(id, &bi) - } else if write.WriteType() == batch.Delete { - id := deserializeUint64(write.Key()) - s.deleteBucketInfo(id) - } - case _liquidStakingBucketTypeNS: - if write.WriteType() == batch.Put { - var bt BucketType - if err = bt.deserialize(write.Value()); err != nil { - return err - } - id := deserializeUint64(write.Key()) - s.putBucketType(id, &bt) - } - } - } - return nil -} - -func (s *liquidStakingCache) putHeight(h uint64) { - s.height = h -} - -func (s *liquidStakingCache) getHeight() uint64 { - return s.height -} - -func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { - amount := bt.Amount.Int64() - s.idBucketTypeMap[id] = bt - m, ok := s.propertyBucketTypeMap[amount] - if !ok { - s.propertyBucketTypeMap[amount] = make(map[int64]uint64) - m = s.propertyBucketTypeMap[amount] - } - m[int64(bt.Duration)] = id -} - -func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { - s.idBucketMap[id] = bi - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) - } - s.candidateBucketMap[bi.Delegate][id] = true -} - -func (s *liquidStakingCache) deleteBucketInfo(id uint64) { - bi, ok := s.idBucketMap[id] - if !ok { - return - } - s.idBucketMap[id] = nil - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - return - } - s.candidateBucketMap[bi.Delegate][id] = false -} - -func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - m, ok := s.propertyBucketTypeMap[amount.Int64()] - if !ok { - return 0, false - } - id, ok := m[int64(duration)] - return id, ok -} - -func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.idBucketTypeMap[id] - return bt, ok -} - -func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { - bt, ok := s.idBucketTypeMap[id] - if !ok { - panic("bucket type not found") - } - return bt -} - -func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.idBucketMap[id] - return bi, ok -} - -func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { - votes := big.NewInt(0) - m, ok := s.candidateBucketMap[name] - if !ok { - return votes - } - for k, v := range m { - if v { - bi, ok := s.idBucketMap[k] - if !ok { - continue - } - if bi.UnstakedAt != nil { - continue - } - bt := s.mustGetBucketType(bi.TypeIndex) - votes.Add(votes, bt.Amount) - } - } - return votes -} - -func newLiquidStakingData(kvStore db.KVStore) (*liquidStakingData, error) { - data := liquidStakingData{ - dirty: batch.NewCachedBatch(), - clean: kvStore, - cleanCache: newLiquidStakingCache(), - dirtyCache: newLiquidStakingCache(), - } - return &data, nil -} - -func (s *liquidStakingIndexer) loadCache() error { - // load height - var height uint64 - h, err := s.clean.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) - if err != nil { - if !errors.Is(err, db.ErrNotExist) { - return err - } - height = 0 - } else { - height = deserializeUint64(h) - } - s.cleanCache.putHeight(height) - - // load bucket info - ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrBucketNotExist) { - return err - } - } - for i := range vs { - var b BucketInfo - if err := b.deserialize(vs[i]); err != nil { - return err - } - s.cleanCache.putBucketInfo(deserializeUint64(ks[i]), &b) - } - - // load bucket type - ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrBucketNotExist) { - return err - } - } - for i := range vs { - var b BucketType - if err := b.deserialize(vs[i]); err != nil { - return err - } - s.cleanCache.putBucketType(deserializeUint64(ks[i]), &b) - } - return nil -} - -func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) - if ok { - return id, true - } - id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) - return id, ok -} - -func (s *liquidStakingIndexer) getBucketTypeCount() uint64 { - base := len(s.cleanCache.idBucketTypeMap) - add := 0 - for k, dbt := range s.dirtyCache.idBucketTypeMap { - _, ok := s.cleanCache.idBucketTypeMap[k] - if dbt != nil && !ok { - add++ - } else if dbt == nil && ok { - add-- - } - } - return uint64(base + add) -} - -func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.dirtyCache.getBucketType(id) - if ok { - return bt, true - } - bt, ok = s.cleanCache.getBucketType(id) - return bt, ok -} - -func (s *liquidStakingIndexer) putHeight(h uint64) { - s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, serializeUint64(h), "failed to put height") - s.dirtyCache.putHeight(h) -} - -func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { - s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") - s.dirtyCache.putBucketType(id, bt) -} - -func (s *liquidStakingIndexer) putBucketInfo(id uint64, bi *BucketInfo) { - s.dirty.Put(_liquidStakingBucketInfoNS, serializeUint64(id), bi.serialize(), "failed to put bucket info") - s.dirtyCache.putBucketInfo(id, bi) -} - -func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.dirtyCache.getBucketInfo(id) - if ok { - return bi, bi != nil - } - bi, ok = s.cleanCache.getBucketInfo(id) - return bi, ok -} - -func (s *liquidStakingIndexer) burnBucket(id uint64) { - s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") - s.dirtyCache.deleteBucketInfo(id) -} - -func (s *liquidStakingIndexer) commit() error { - if err := s.cleanCache.writeBatch(s.dirty); err != nil { - return err - } - if err := s.clean.WriteBatch(s.dirty); err != nil { - return err - } - s.dirty.Lock() - s.dirty.ClearAndUnlock() - s.dirtyCache = newLiquidStakingCache() - return nil -} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 8217464981..5970e6f47e 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -1306,7 +1306,7 @@ type ( Duration time.Duration ActivatedAt *time.Time } - // Bucket is the bucket information + // Bucket is the bucket information including bucket type and bucket info Bucket struct { Index uint64 Candidate string @@ -1322,6 +1322,21 @@ type ( // eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type // TODO: this is general enough to be moved to a common package eventParam map[string]any + + liquidStakingCache struct { + idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo + candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket + idBucketTypeMap map[uint64]*BucketType // map[token]BucketType + propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + height uint64 + } + + liquidStakingDataStore struct { + dirty batch.CachedBatch // batch for dirty data + kvstore db.KVStore // persistent storage + dirtyCache *liquidStakingCache // in-memory index for dirty data + cleanCache *liquidStakingCache // in-memory index for clean data + } ) var ( @@ -1749,6 +1764,126 @@ func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { return nil } +func (s *liquidStakingIndexer) loadCache() error { + // load height + var height uint64 + h, err := s.clean.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) + if err != nil { + if !errors.Is(err, db.ErrNotExist) { + return err + } + height = 0 + } else { + height = deserializeUint64(h) + } + s.cleanCache.putHeight(height) + + // load bucket info + ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) + if err != nil { + if !errors.Is(err, db.ErrBucketNotExist) { + return err + } + } + for i := range vs { + var b BucketInfo + if err := b.deserialize(vs[i]); err != nil { + return err + } + s.cleanCache.putBucketInfo(deserializeUint64(ks[i]), &b) + } + + // load bucket type + ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) + if err != nil { + if !errors.Is(err, db.ErrBucketNotExist) { + return err + } + } + for i := range vs { + var b BucketType + if err := b.deserialize(vs[i]); err != nil { + return err + } + s.cleanCache.putBucketType(deserializeUint64(ks[i]), &b) + } + return nil +} + +func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) + if ok { + return id, true + } + id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) + return id, ok +} + +func (s *liquidStakingIndexer) getBucketTypeCount() uint64 { + base := len(s.cleanCache.idBucketTypeMap) + add := 0 + for k, dbt := range s.dirtyCache.idBucketTypeMap { + _, ok := s.cleanCache.idBucketTypeMap[k] + if dbt != nil && !ok { + add++ + } else if dbt == nil && ok { + add-- + } + } + return uint64(base + add) +} + +func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.dirtyCache.getBucketType(id) + if ok { + return bt, true + } + bt, ok = s.cleanCache.getBucketType(id) + return bt, ok +} + +func (s *liquidStakingIndexer) putHeight(h uint64) { + s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, serializeUint64(h), "failed to put height") + s.dirtyCache.putHeight(h) +} + +func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { + s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") + s.dirtyCache.putBucketType(id, bt) +} + +func (s *liquidStakingIndexer) putBucketInfo(id uint64, bi *BucketInfo) { + s.dirty.Put(_liquidStakingBucketInfoNS, serializeUint64(id), bi.serialize(), "failed to put bucket info") + s.dirtyCache.putBucketInfo(id, bi) +} + +func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.dirtyCache.getBucketInfo(id) + if ok { + return bi, bi != nil + } + bi, ok = s.cleanCache.getBucketInfo(id) + return bi, ok +} + +func (s *liquidStakingIndexer) burnBucket(id uint64) { + s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") + s.dirtyCache.deleteBucketInfo(id) +} + +func (s *liquidStakingIndexer) commit() error { + if err := s.cleanCache.writeBatch(s.dirty); err != nil { + return err + } + if err := s.clean.WriteBatch(s.dirty); err != nil { + return err + } + s.dirty.Lock() + s.dirty.ClearAndUnlock() + s.dirtyCache = newLiquidStakingCache() + return nil +} + func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { return time.Duration(height) * s.blockInterval } @@ -1873,6 +2008,146 @@ func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { return nil } +func newLiquidStakingCache() *liquidStakingCache { + return &liquidStakingCache{ + idBucketMap: make(map[uint64]*BucketInfo), + idBucketTypeMap: make(map[uint64]*BucketType), + propertyBucketTypeMap: make(map[int64]map[int64]uint64), + candidateBucketMap: make(map[string]map[uint64]bool), + } +} + +func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { + for i := 0; i < b.Size(); i++ { + write, err := b.Entry(i) + if err != nil { + return err + } + switch write.Namespace() { + case _liquidStakingBucketInfoNS: + if write.WriteType() == batch.Put { + var bi BucketInfo + if err = bi.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketInfo(id, &bi) + } else if write.WriteType() == batch.Delete { + id := deserializeUint64(write.Key()) + s.deleteBucketInfo(id) + } + case _liquidStakingBucketTypeNS: + if write.WriteType() == batch.Put { + var bt BucketType + if err = bt.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketType(id, &bt) + } + } + } + return nil +} + +func (s *liquidStakingCache) putHeight(h uint64) { + s.height = h +} + +func (s *liquidStakingCache) getHeight() uint64 { + return s.height +} + +func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { + amount := bt.Amount.Int64() + s.idBucketTypeMap[id] = bt + m, ok := s.propertyBucketTypeMap[amount] + if !ok { + s.propertyBucketTypeMap[amount] = make(map[int64]uint64) + m = s.propertyBucketTypeMap[amount] + } + m[int64(bt.Duration)] = id +} + +func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { + s.idBucketMap[id] = bi + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) + } + s.candidateBucketMap[bi.Delegate][id] = true +} + +func (s *liquidStakingCache) deleteBucketInfo(id uint64) { + bi, ok := s.idBucketMap[id] + if !ok { + return + } + s.idBucketMap[id] = nil + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + return + } + s.candidateBucketMap[bi.Delegate][id] = false +} + +func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + m, ok := s.propertyBucketTypeMap[amount.Int64()] + if !ok { + return 0, false + } + id, ok := m[int64(duration)] + return id, ok +} + +func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.idBucketTypeMap[id] + return bt, ok +} + +func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { + bt, ok := s.idBucketTypeMap[id] + if !ok { + panic("bucket type not found") + } + return bt +} + +func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.idBucketMap[id] + return bi, ok +} + +func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { + votes := big.NewInt(0) + m, ok := s.candidateBucketMap[name] + if !ok { + return votes + } + for k, v := range m { + if v { + bi, ok := s.idBucketMap[k] + if !ok { + continue + } + if bi.UnstakedAt != nil { + continue + } + bt := s.mustGetBucketType(bi.TypeIndex) + votes.Add(votes, bt.Amount) + } + } + return votes +} + +func newLiquidStakingDataStore(kvStore db.KVStore) (*liquidStakingDataStore, error) { + data := liquidStakingDataStore{ + dirty: batch.NewCachedBatch(), + kvstore: kvStore, + cleanCache: newLiquidStakingCache(), + dirtyCache: newLiquidStakingCache(), + } + return &data, nil +} + func serializeUint64(v uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, v) @@ -1918,13 +2193,6 @@ func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) } } // unpack indexed fields - // i := 0 - // for _, arg := range abiEvent.Inputs { - // if arg.Indexed { - // i++ - // event[arg.Name] = log.Topics[i] - // } - // } args := make(abi.Arguments, 0) for _, arg := range abiEvent.Inputs { if arg.Indexed { diff --git a/blockindex/liquidstaking_indexer_test.go b/blockindex/liquidstaking_indexer_test.go deleted file mode 100644 index a7d9015130..0000000000 --- a/blockindex/liquidstaking_indexer_test.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2023 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package blockindex - -import "testing" - -func TestLiquidStakingIndexer(t *testing.T) { - -} diff --git a/chainservice/builder.go b/chainservice/builder.go index be5aa0cf40..d69620ab86 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -246,7 +246,7 @@ func (builder *Builder) buildBlockDAO(forTest bool) error { } var indexers []blockdao.BlockIndexer - indexers = append(indexers, builder.cs.factory, builder.cs.liquidStakingIndexer) + indexers = append(indexers, builder.cs.factory) if !builder.cfg.Chain.EnableAsyncIndexWrite && builder.cs.indexer != nil { indexers = append(indexers, builder.cs.indexer) } @@ -266,7 +266,7 @@ func (builder *Builder) buildBlockDAO(forTest bool) error { } func (builder *Builder) buildGatewayComponents(forTest bool) error { - indexer, bfIndexer, candidateIndexer, candBucketsIndexer, liquidStakeBucketsIndexer, err := builder.createGateWayComponents(forTest) + indexer, bfIndexer, candidateIndexer, candBucketsIndexer, err := builder.createGateWayComponents(forTest) if err != nil { return errors.Wrapf(err, "failed to create gateway components") } @@ -280,10 +280,6 @@ func (builder *Builder) buildGatewayComponents(forTest bool) error { } builder.cs.bfIndexer = bfIndexer builder.cs.indexer = indexer - builder.cs.liquidStakingIndexer = liquidStakeBucketsIndexer - // if builder.cs.liquidStakingIndexer != nil { - // builder.cs.lifecycle.Add(builder.cs.liquidStakingIndexer) - // } return nil } @@ -292,7 +288,6 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( bfIndexer blockindex.BloomFilterIndexer, candidateIndexer *poll.CandidateIndexer, candBucketsIndexer *staking.CandidatesBucketsIndexer, - liquidStakeBucketsIndexer blockindex.LiquidStakingIndexer, err error, ) { _, gateway := builder.cfg.Plugins[config.GatewayPlugin] @@ -316,7 +311,6 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( if builder.cfg.Chain.EnableStakingIndexer { candBucketsIndexer, err = staking.NewStakingCandidatesBucketsIndexer(db.NewMemKVStore()) } - liquidStakeBucketsIndexer = blockindex.NewLiquidStakingIndexer(db.NewMemKVStore(), builder.cfg.Genesis.BlockInterval) return } dbConfig := builder.cfg.DB @@ -345,10 +339,6 @@ func (builder *Builder) createGateWayComponents(forTest bool) ( dbConfig.DbPath = builder.cfg.Chain.StakingIndexDBPath candBucketsIndexer, err = staking.NewStakingCandidatesBucketsIndexer(db.NewBoltDB(dbConfig)) } - - // create liquid staking indexer - dbConfig.DbPath = builder.cfg.Chain.LiquidStakingIndexDBPath - liquidStakeBucketsIndexer = blockindex.NewLiquidStakingIndexer(db.NewBoltDB(dbConfig), builder.cfg.Genesis.BlockInterval) return } diff --git a/chainservice/chainservice.go b/chainservice/chainservice.go index 0e27f6e004..fc41d3339d 100644 --- a/chainservice/chainservice.go +++ b/chainservice/chainservice.go @@ -80,13 +80,12 @@ type ChainService struct { p2pAgent p2p.Agent electionCommittee committee.Committee // TODO: explorer dependency deleted at #1085, need to api related params - indexer blockindex.Indexer - bfIndexer blockindex.BloomFilterIndexer - candidateIndexer *poll.CandidateIndexer - candBucketsIndexer *staking.CandidatesBucketsIndexer - registry *protocol.Registry - nodeInfoManager *nodeinfo.InfoManager - liquidStakingIndexer blockindex.LiquidStakingIndexer + indexer blockindex.Indexer + bfIndexer blockindex.BloomFilterIndexer + candidateIndexer *poll.CandidateIndexer + candBucketsIndexer *staking.CandidatesBucketsIndexer + registry *protocol.Registry + nodeInfoManager *nodeinfo.InfoManager } // Start starts the server diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index fb6153ccec..0c02f899a3 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -374,7 +374,6 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r defer testutil.CleanupPath(testLiquidStakeIndexerPath) cfg.Chain.TrieDBPath = testTriePath - cfg.Chain.LiquidStakingIndexDBPath = testLiquidStakeIndexerPath cfg.ActPool.MinGasPriceStr = "0" cfg.Genesis.Blockchain.AleutianBlockHeight = 0 diff --git a/e2etest/staking_test.go b/e2etest/staking_test.go index f4774ed19e..98075e9296 100644 --- a/e2etest/staking_test.go +++ b/e2etest/staking_test.go @@ -33,11 +33,6 @@ import ( "github.com/iotexproject/iotex-core/testutil" ) -func TestAAA(t *testing.T) { - t.Log(identityset.Address(1)) - t.Log(identityset.PrivateKey(1).HexString()) -} - func TestStakingContract(t *testing.T) { require := require.New(t) diff --git a/go.mod b/go.mod index a5ba735674..1e50b2391c 100644 --- a/go.mod +++ b/go.mod @@ -54,6 +54,7 @@ require ( ) require ( + github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce github.com/cespare/xxhash/v2 v2.1.2 github.com/holiman/uint256 v1.2.0 github.com/prometheus/client_model v0.2.0 @@ -71,7 +72,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.21.0-beta // indirect github.com/btcsuite/btcd/btcec/v2 v2.1.2 // indirect - github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set v1.8.0 // indirect From 44a4a2201477d9ddde0e0a01229ea4c4e88e68f7 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 27 Apr 2023 21:49:27 +0800 Subject: [PATCH 17/51] refactor --- chainservice/builder.go | 1 + 1 file changed, 1 insertion(+) diff --git a/chainservice/builder.go b/chainservice/builder.go index d69620ab86..ef44f1ce33 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -280,6 +280,7 @@ func (builder *Builder) buildGatewayComponents(forTest bool) error { } builder.cs.bfIndexer = bfIndexer builder.cs.indexer = indexer + return nil } From d4b92cffb4ef16cc05d00b50583374390e76ce84 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 27 Apr 2023 22:03:50 +0800 Subject: [PATCH 18/51] refactor --- blockindex/liquidstaking_indexer.go | 44 ++++++++++------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 5970e6f47e..0ca81b9b09 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -1282,12 +1282,13 @@ type ( } liquidStakingIndexer struct { + dirty batch.CachedBatch // batch for dirty data + kvstore db.KVStore // persistent storage + dirtyCache *liquidStakingCache // in-memory index for dirty data + cleanCache *liquidStakingCache // in-memory index for clean data + + tokenOwner map[uint64]string // token id -> owner blockInterval time.Duration - dirty batch.CachedBatch // im-memory dirty data - dirtyCache *liquidStakingCache - clean db.KVStore // clean data in db - cleanCache *liquidStakingCache // in-memory index for clean data - tokenOwner map[uint64]string // token id -> owner } // BucketInfo is the bucket information @@ -1306,6 +1307,7 @@ type ( Duration time.Duration ActivatedAt *time.Time } + // Bucket is the bucket information including bucket type and bucket info Bucket struct { Index uint64 @@ -1330,13 +1332,6 @@ type ( propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index height uint64 } - - liquidStakingDataStore struct { - dirty batch.CachedBatch // batch for dirty data - kvstore db.KVStore // persistent storage - dirtyCache *liquidStakingCache // in-memory index for dirty data - cleanCache *liquidStakingCache // in-memory index for clean data - } ) var ( @@ -1345,6 +1340,7 @@ var ( errInvlidEventParam = errors.New("invalid event param") errBucketTypeNotExist = errors.New("bucket type does not exist") + // ErrBucketInfoNotExist is the error when bucket does not exist ErrBucketInfoNotExist = errors.New("bucket info does not exist") ) @@ -1363,21 +1359,21 @@ func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) Li blockInterval: blockInterval, dirty: batch.NewCachedBatch(), dirtyCache: newLiquidStakingCache(), - clean: kvStore, + kvstore: kvStore, cleanCache: newLiquidStakingCache(), tokenOwner: make(map[uint64]string), } } func (s *liquidStakingIndexer) Start(ctx context.Context) error { - if err := s.clean.Start(ctx); err != nil { + if err := s.kvstore.Start(ctx); err != nil { return err } return s.loadCache() } func (s *liquidStakingIndexer) Stop(ctx context.Context) error { - if err := s.clean.Stop(ctx); err != nil { + if err := s.kvstore.Stop(ctx); err != nil { return err } return nil @@ -1767,7 +1763,7 @@ func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { func (s *liquidStakingIndexer) loadCache() error { // load height var height uint64 - h, err := s.clean.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) + h, err := s.kvstore.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) if err != nil { if !errors.Is(err, db.ErrNotExist) { return err @@ -1779,7 +1775,7 @@ func (s *liquidStakingIndexer) loadCache() error { s.cleanCache.putHeight(height) // load bucket info - ks, vs, err := s.clean.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) + ks, vs, err := s.kvstore.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { if !errors.Is(err, db.ErrBucketNotExist) { return err @@ -1794,7 +1790,7 @@ func (s *liquidStakingIndexer) loadCache() error { } // load bucket type - ks, vs, err = s.clean.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) + ks, vs, err = s.kvstore.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { if !errors.Is(err, db.ErrBucketNotExist) { return err @@ -1875,7 +1871,7 @@ func (s *liquidStakingIndexer) commit() error { if err := s.cleanCache.writeBatch(s.dirty); err != nil { return err } - if err := s.clean.WriteBatch(s.dirty); err != nil { + if err := s.kvstore.WriteBatch(s.dirty); err != nil { return err } s.dirty.Lock() @@ -2138,16 +2134,6 @@ func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { return votes } -func newLiquidStakingDataStore(kvStore db.KVStore) (*liquidStakingDataStore, error) { - data := liquidStakingDataStore{ - dirty: batch.NewCachedBatch(), - kvstore: kvStore, - cleanCache: newLiquidStakingCache(), - dirtyCache: newLiquidStakingCache(), - } - return &data, nil -} - func serializeUint64(v uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, v) From 3850ccd9563a6d389f8d95112fd027a34f99497d Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 27 Apr 2023 22:51:18 +0800 Subject: [PATCH 19/51] remove indexed merge param --- blockindex/liquidstaking_indexer.go | 1168 ++++++++++++++------------- e2etest/liquid_staking_test.go | 31 +- 2 files changed, 616 insertions(+), 583 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 0ca81b9b09..e3870217d3 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -34,42 +34,6 @@ const ( LiquidStakingContractAddress = "io1dkqh5mu9djfas3xyrmzdv9frsmmytel4mp7a64" // LiquidStakingContractABI is the ABI of liquid staking contract LiquidStakingContractABI = `[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "activateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "addBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "stateMutability": "nonpayable", @@ -144,24 +108,6 @@ const ( "name": "ApprovalForAll", "type": "event" }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "anonymous": false, "inputs": [ @@ -200,60 +146,6 @@ const ( "name": "BucketTypeDeactivated", "type": "event" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegates", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "deactivateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "anonymous": false, "inputs": [ @@ -292,78 +184,6 @@ const ( "name": "DurationExtended", "type": "event" }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newDuration", - "type": "uint256" - } - ], - "name": "extendDuration", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newAmount", - "type": "uint256" - } - ], - "name": "increaseAmount", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "lock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "lock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "anonymous": false, "inputs": [ @@ -383,29 +203,11 @@ const ( "name": "Locked", "type": "event" }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "_newDuration", - "type": "uint256" - } - ], - "name": "merge", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, { "anonymous": false, "inputs": [ { - "indexed": true, + "indexed": false, "internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]" @@ -445,13 +247,6 @@ const ( "name": "OwnershipTransferred", "type": "event" }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "anonymous": false, "inputs": [ @@ -466,231 +261,183 @@ const ( "type": "event" }, { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "from", - "type": "address" + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" }, { - "internalType": "address", - "name": "to", - "type": "address" + "indexed": false, + "internalType": "bytes12", + "name": "delegate", + "type": "bytes12" }, { + "indexed": false, "internalType": "uint256", - "name": "tokenId", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", "type": "uint256" } ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "Staked", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { + "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { + "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" } ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "Transfer", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" } ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "name": "Unlocked", + "type": "event" }, { + "anonymous": false, "inputs": [ { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" } ], - "name": "stake", - "outputs": [ + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ { + "indexed": true, "internalType": "uint256", - "name": "", + "name": "tokenId", "type": "uint256" } ], - "stateMutability": "payable", - "type": "function" + "name": "Unstaked", + "type": "event" }, { + "anonymous": false, "inputs": [ { + "indexed": true, "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", + "name": "tokenId", "type": "uint256" }, { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" } ], - "name": "stake", + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [], + "name": "UINT256_MAX", "outputs": [ { "internalType": "uint256", - "name": "firstTokenId_", + "name": "", "type": "uint256" } ], - "stateMutability": "payable", + "stateMutability": "view", "type": "function" }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "stake", + "inputs": [], + "name": "UNSTAKE_FREEZE_BLOCKS", "outputs": [ { "internalType": "uint256", - "name": "firstTokenId_", + "name": "", "type": "uint256" } ], - "stateMutability": "payable", + "stateMutability": "view", "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes12", - "name": "delegate", - "type": "bytes12" - }, - { - "indexed": false, "internalType": "uint256", - "name": "amount", + "name": "_amount", "type": "uint256" }, { - "indexed": false, "internalType": "uint256", - "name": "duration", + "name": "_duration", "type": "uint256" } ], - "name": "Staked", - "type": "event" + "name": "activateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" + "internalType": "uint256", + "name": "_amount", + "type": "uint256" }, { - "indexed": true, "internalType": "uint256", - "name": "tokenId", + "name": "_duration", "type": "uint256" } ], - "name": "Transfer", - "type": "event" + "name": "addBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, { "internalType": "address", "name": "to", @@ -702,7 +449,7 @@ const ( "type": "uint256" } ], - "name": "transferFrom", + "name": "approve", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -711,26 +458,19 @@ const ( "inputs": [ { "internalType": "address", - "name": "newOwner", + "name": "owner", "type": "address" } ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "balanceOf", + "outputs": [ { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -741,44 +481,17 @@ const ( "type": "uint256" } ], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ + "name": "blocksToUnstake", + "outputs": [ { - "indexed": true, "internalType": "uint256", - "name": "tokenId", + "name": "", "type": "uint256" } ], - "name": "Unlocked", - "type": "event" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, { "inputs": [ { @@ -787,52 +500,112 @@ const ( "type": "uint256" } ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ + "name": "blocksToWithdraw", + "outputs": [ { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" + "internalType": "uint256", + "name": "", + "type": "uint256" } ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "uint256", - "name": "tokenId", + "name": "_tokenId", "type": "uint256" } ], - "name": "Unstaked", - "type": "event" - }, - { - "inputs": [ + "name": "bucketOf", + "outputs": [ { "internalType": "uint256", - "name": "_tokenId", + "name": "amount_", "type": "uint256" }, { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], + "internalType": "uint256", + "name": "duration_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unlockedAt_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unstakedAt_", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "delegate_", + "type": "bytes12" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + } + ], + "name": "bucketTypes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activatedAt", + "type": "uint256" + } + ], + "internalType": "struct BucketType[]", + "name": "types_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegate", + "outputs": [], "stateMutability": "nonpayable", "type": "function" }, @@ -844,51 +617,68 @@ const ( "type": "uint256[]" }, { - "internalType": "address payable", - "name": "_recipient", - "type": "address" + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" } ], - "name": "withdraw", + "name": "changeDelegates", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { - "anonymous": false, "inputs": [ { - "indexed": true, "internalType": "uint256", - "name": "tokenId", + "name": "_amount", "type": "uint256" }, { - "indexed": true, - "internalType": "address", - "name": "recipient", - "type": "address" + "internalType": "uint256", + "name": "_duration", + "type": "uint256" } ], - "name": "Withdrawal", - "type": "event" + "name": "deactivateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" } ], - "name": "balanceOf", - "outputs": [ + "name": "extendDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "tokenId", "type": "uint256" } ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], "stateMutability": "view", "type": "function" }, @@ -898,33 +688,61 @@ const ( "internalType": "uint256", "name": "_tokenId", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newAmount", + "type": "uint256" } ], - "name": "blocksToUnstake", - "outputs": [ + "name": "increaseAmount", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", "type": "uint256" } ], + "name": "isActiveBucketType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], "stateMutability": "view", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" } ], - "name": "blocksToWithdraw", + "name": "isApprovedForAll", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -936,97 +754,249 @@ const ( "internalType": "uint256", "name": "_tokenId", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" } ], - "name": "bucketOf", - "outputs": [ + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, { "internalType": "uint256", - "name": "amount_", + "name": "_duration", "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "lockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" }, { "internalType": "uint256", - "name": "duration_", + "name": "_newDuration", "type": "uint256" - }, + } + ], + "name": "merge", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfBucketTypes", + "outputs": [ { "internalType": "uint256", - "name": "unlockedAt_", + "name": "", "type": "uint256" - }, + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "unstakedAt_", + "name": "tokenId", "type": "uint256" - }, + } + ], + "name": "ownerOf", + "outputs": [ { - "internalType": "bytes12", - "name": "delegate_", - "type": "bytes12" + "internalType": "address", + "name": "", + "type": "address" } ], "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, { "internalType": "uint256", - "name": "_offset", + "name": "tokenId", "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" }, { "internalType": "uint256", - "name": "_size", + "name": "tokenId", "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" } ], - "name": "bucketTypes", - "outputs": [ + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "components": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "duration", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "activatedAt", - "type": "uint256" - } - ], - "internalType": "struct BucketType[]", - "name": "types_", - "type": "tuple[]" + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" } ], - "stateMutability": "view", + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", - "name": "tokenId", + "name": "_duration", "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" } ], - "name": "getApproved", + "name": "stake", "outputs": [ { - "internalType": "address", + "internalType": "uint256", "name": "", - "type": "address" + "type": "uint256" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { @@ -1040,57 +1010,72 @@ const ( "internalType": "uint256", "name": "_duration", "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" } ], - "name": "isActiveBucketType", + "name": "stake", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { "inputs": [ { - "internalType": "address", - "name": "owner", - "type": "address" + "internalType": "uint256", + "name": "_amount", + "type": "uint256" }, { - "internalType": "address", - "name": "operator", - "type": "address" + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" } ], - "name": "isApprovedForAll", + "name": "stake", "outputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" } ], - "stateMutability": "view", + "stateMutability": "payable", "type": "function" }, { "inputs": [ { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" } ], - "name": "lockedVotesTo", + "name": "supportsInterface", "outputs": [ { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" + "internalType": "bool", + "name": "", + "type": "bool" } ], "stateMutability": "view", @@ -1098,7 +1083,7 @@ const ( }, { "inputs": [], - "name": "name", + "name": "symbol", "outputs": [ { "internalType": "string", @@ -1110,26 +1095,19 @@ const ( "type": "function" }, { - "inputs": [], - "name": "numOfBucketTypes", - "outputs": [ + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "tokenId", "type": "uint256" } ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", + "name": "tokenURI", "outputs": [ { - "internalType": "address", + "internalType": "string", "name": "", - "type": "address" + "type": "string" } ], "stateMutability": "view", @@ -1138,81 +1116,79 @@ const ( { "inputs": [ { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ + "internalType": "address", + "name": "from", + "type": "address" + }, { "internalType": "address", - "name": "", + "name": "to", "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" } ], - "stateMutability": "view", + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "paused", - "outputs": [ + "inputs": [ { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "address", + "name": "newOwner", + "type": "address" } ], - "stateMutability": "view", + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" } ], - "stateMutability": "view", + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "symbol", - "outputs": [ + "inputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" } ], - "stateMutability": "view", + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" } ], - "name": "tokenURI", + "name": "unlockedVotesTo", "outputs": [ { - "internalType": "string", - "name": "", - "type": "string" + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" } ], "stateMutability": "view", @@ -1220,47 +1196,71 @@ const ( }, { "inputs": [], - "name": "UINT256_MAX", - "outputs": [ + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { "internalType": "uint256", - "name": "", + "name": "_tokenId", "type": "uint256" } ], - "stateMutability": "view", + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" } ], - "name": "unlockedVotesTo", - "outputs": [ + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" } ], - "stateMutability": "view", + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { - "inputs": [], - "name": "UNSTAKE_FREEZE_BLOCKS", - "outputs": [ + "inputs": [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" } ], - "stateMutability": "view", + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" } ]` @@ -1864,7 +1864,7 @@ func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { func (s *liquidStakingIndexer) burnBucket(id uint64) { s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") - s.dirtyCache.deleteBucketInfo(id) + s.dirtyCache.markDeleteBucketInfo(id) } func (s *liquidStakingIndexer) commit() error { @@ -2074,6 +2074,18 @@ func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { } func (s *liquidStakingCache) deleteBucketInfo(id uint64) { + bi, ok := s.idBucketMap[id] + if !ok { + return + } + delete(s.idBucketMap, id) + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + return + } + delete(s.candidateBucketMap[bi.Delegate], id) +} + +func (s *liquidStakingCache) markDeleteBucketInfo(id uint64) { bi, ok := s.idBucketMap[id] if !ok { return diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 0c02f899a3..f483cd35c0 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -32,10 +32,11 @@ import ( "github.com/iotexproject/iotex-core/testutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" ) const ( - _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b2366004613430565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613476565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613493565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134fc565b34801561034a57600080fd5b5061035e610359366004613493565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b761039136600461350f565b610ab4565b3480156103a257600080fd5b506102b76103b136600461353b565b610bc9565b3480156103c257600080fd5b506102b76103d136600461355d565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135bb565b610c6d565b34801561040257600080fd5b506102b7610411366004613493565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b610446366004613632565b610d9c565b6040516102e59190613673565b34801561046457600080fd5b506102b761047336600461355d565b610f18565b34801561048457600080fd5b50610498610493366004613493565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e536600461353b565b610fa9565b61030e6104f83660046135bb565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136fd565b61103a565b34801561054857600080fd5b506102b7610557366004613632565b6110e1565b34801561056857600080fd5b506102b7610577366004613493565b611177565b34801561058857600080fd5b5061035e610597366004613493565b6111d9565b3480156105a857600080fd5b5061044b6105b7366004613632565b611239565b3480156105c857600080fd5b5061030e6105d7366004613748565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c36600461353b565b611445565b6040516102e59190613765565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613493565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137be565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137f1565b6115d3565b6102b76106e936600461353b565b61166a565b3480156106fa57600080fd5b506102b761070936600461388a565b611772565b34801561071a57600080fd5b506102b761072936600461394d565b6117aa565b6102b761073c3660046136fd565b611899565b34801561074d57600080fd5b5061033161075c366004613493565b611ab3565b34801561076d57600080fd5b506102b761077c36600461353b565b611b26565b61030e61078f3660046139a3565b611ccb565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c536600461353b565b611d95565b61030e6107d83660046139e0565b611e7e565b3480156107e957600080fd5b506102b76107f836600461353b565b611f70565b34801561080957600080fd5b506102b7610818366004613632565b611fe4565b34801561082957600080fd5b506102d9610838366004613aa1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b761088136600461353b565b6120c0565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613748565b612136565b6108c46121af565b816108ce816121fc565b600083815260086020526040902060028101546108ea90612251565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122c6565b6109478184612369565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612428565b6000828152600860205260409020600201546109cf90612251565b606060008054610a0a90613acf565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613acf565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612428565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612487565b505050565b610bd16121af565b81610bdb816121fc565b6000838152600860205260409020610bf2816124f5565b610bfc818461253f565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612627565b610c625760405162461bcd60e51b815260040161092b90613b09565b610bc48383836126a5565b610c756121af565b81610c7f816121fc565b6000838152600860205260409020610c979083612816565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce36121af565b80610ced816121fc565b6000828152600860205260409020610d04816124f5565b610d0d81612919565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129f9565b610d9a612a53565b565b6060816001600160401b03811115610db657610db6613844565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613844565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b56565b6020026020010181905250600060096000878785818110610e7b57610e7b613b56565b9050602002016020810190610e909190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b56565b60200260200101518281518110610ef357610ef3613b56565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612428565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b56565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612aa8565b612b0f565b9392505050565b6000610fce6121af565b346000610fdb8286612aa8565b9050610fe681612b40565b610ff08185612b8c565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b87565b60405180910390a295945050505050565b6110426121af565b60008060005b848110156110d95785858281811061106257611062613b56565b905060200201359250611074836121fc565b6000838152600860205260409020915061108d826124f5565b611097828561253f565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e96121af565b60008060005b838110156111705784848281811061110957611109613b56565b90506020020135925061111b836121fc565b6000838152600860205260409020915061113482612c2c565b61113d82612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f6121af565b80611189816121fc565b60008281526008602052604090206111a081612c2c565b6111a981612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613844565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613844565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b56565b60200260200101819052506000600a600087878581811061131857611318613b56565b905060200201602081019061132d9190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b56565b6020026020010151828151811061139057611390613b56565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129f9565b610d9a6000612cce565b60606000821180156114625750600b5461145f8385613bbf565b11155b61147e5760405162461bcd60e51b815260040161092b90613bd2565b816001600160401b0381111561149657611496613844565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b56565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b56565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129f9565b610d9a612d20565b600061159582612428565b60008281526008602052604090206115ac816124f5565b610fbd81612919565b606060018054610a0a90613acf565b6115cf338383612d63565b5050565b6115db6121af565b6000805b83811015611170578484828181106115f9576115f9613b56565b90506020020135915061160b826121fc565b60008281526008602052604090206116239084612816565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b6116726121af565b8161167c816121fc565b600083815260086020526040902061169381612c2c565b8054600b805460009190839081106116ad576116ad613b56565b90600052602060002090600302019050848160000154346116ce9190613bbf565b146116eb5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e31565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612627565b6117985760405162461bcd60e51b815260040161092b90613b09565b6117a484848484612e81565b50505050565b6117b26121af565b60008060005b848110156110d9578585828181106117d2576117d2613b56565b9050602002013592506117e4836121fc565b6000838152600860205260409020600281015490925061180390612251565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122c6565b61185b8285612369565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a16121af565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611aa9576000190187878281811061190557611905613b56565b905060200201359350611917846121fc565b60008481526008602052604090209250611930836124f5565b82546003840154600b805460a09290921b918390811061195257611952613b56565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bbf565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122c6565b611aa2565b6000196001860155611a5185888a612e31565b8989604051611a61929190613c29565b60408051918290038220898352602083018b9052917fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12910160405180910390a25b50506118e9565b5050505050505050565b6060611abe82612428565b6000611ad560408051602081019091526000815290565b90506000815111611af55760405180602001604052806000815250610fbd565b80611aff84612eb4565b604051602001611b10929190613c52565b6040516020818303038152906040529392505050565b611b2e6129f9565b81600003611b725760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bd15760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cd56121af565b600082118015611ced575034611ceb8387613c81565b145b611d095760405162461bcd60e51b815260040161092b90613bd2565b6000611d158686612aa8565b9050611d2081612b40565b600754600101915060005b83811015611d8a57611d3d8286612b8c565b611d478184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d7a93929190613b87565b60405180910390a2600101611d2b565b50505b949350505050565b611d9d6121af565b81611da7816121fc565b6000838152600860205260409020611dbe81612c2c565b8054600b80546000919083908110611dd857611dd8613b56565b9060005260206000209060030201905080600101548511611e0b5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e4c90849087612e31565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e886121af565b34825185611e969190613c81565b14611eb35760405162461bcd60e51b815260040161092b90613bd2565b6000611ebf8585612aa8565b9050611eca81612b40565b600754600101915060005b8351811015611f6757611f0182858381518110611ef457611ef4613b56565b6020026020010151612b8c565b611f0b8184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f3e57611f3e613b56565b60200260200101518888604051611f5793929190613b87565b60405180910390a2600101611ed5565b50509392505050565b611f786129f9565b43600b611f858484612aa8565b81548110611f9557611f95613b56565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cbf929190918252602082015260400190565b611fec6121af565b60008060005b838110156111705784848281811061200c5761200c613b56565b90506020020135925061201e836121fc565b60008381526008602052604090209150612037826124f5565b61204082612919565b156120845760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61208d826129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611ff2565b6120c86129f9565b600019600b6120d78484612aa8565b815481106120e7576120e7613b56565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cbf929190918252602082015260400190565b61213e6129f9565b6001600160a01b0381166121a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b6121ac81612cce565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b612205816111d9565b6001600160a01b0316336001600160a01b0316146121ac5760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361229d5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b60006122ab61ca8084613bbf565b90504381116122bd5750600092915050565b43900392915050565b60006122d1826111d9565b90506122e1816000846001612f46565b6122ea826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061238257612382613b56565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121ac5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124bc826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61255284612919565b8310156125945760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125c4600b84815481106125ac576125ac613b56565b90600052602060002090600302016000015485612aa8565b90506125cf81612b40565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612633836111d9565b9050806001600160a01b0316846001600160a01b0316148061267a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d8d5750836001600160a01b031661269384610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126b8826111d9565b6001600160a01b0316146126de5760405162461bcd60e51b815260040161092b90613c98565b6001600160a01b0382166127405760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61274d8383836001612f46565b826001600160a01b0316612760826111d9565b6001600160a01b0316146127865760405162461bcd60e51b815260040161092b90613c98565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61281f826124f5565b8154600383015460a01b6001600160a01b0319808416908216036128555760405162461bcd60e51b815260040161092b90613bfe565b6001840154600019146128ac576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128f2565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b6001810154600090600019810361296b5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061298457612984613b56565b906000526020600020906003020160010154826129a19190613bbf565b90504381116129b4575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a5b61300f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b055760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d8d565b600043600b8381548110612b2557612b25613b56565b90600052602060002090600302016002015411159050919050565b612b4981612b0f565b6121ac5760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061305f565b6001810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d286121af565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a8b3390565b816001600160a01b0316836001600160a01b031603612dc45760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e3d8383612aa8565b9050612e4881612b40565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e8c8484846126a5565b612e9884848484613079565b6117a45760405162461bcd60e51b815260040161092b90613cdd565b60606000612ec183613177565b60010190506000816001600160401b03811115612ee057612ee0613844565b6040519080825280601f01601f191660200182016040528015612f0a576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f1457509392505050565b80600114612f965760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fbe5750600082815260086020526040902060020154600019145b61300a5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061324f565b60006001600160a01b0384163b1561316f57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130bd903390899088908890600401613d2f565b6020604051808303816000875af19250505080156130f8575060408051601f3d908101601f191682019092526130f591810190613d6c565b60015b613155573d808015613126576040519150601f19603f3d011682016040523d82523d6000602084013e61312b565b606091505b50805160000361314d5760405162461bcd60e51b815260040161092b90613cdd565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d8d565b506001611d8d565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131b65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131e2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061320057662386f26fc10000830492506010015b6305f5e1008310613218576305f5e100830492506008015b612710831061322c57612710830492506004015b6064831061323e576064830492506002015b600a83106109cf5760010192915050565b6132598383613282565b6132666000848484613079565b610bc45760405162461bcd60e51b815260040161092b90613cdd565b6001600160a01b0382166132d85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561333d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b61334b600083836001612f46565b6000818152600260205260409020546001600160a01b0316156133b05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121ac57600080fd5b6000806040838503121561344357600080fd5b8235915060208301356134558161341b565b809150509250929050565b6001600160e01b0319811681146121ac57600080fd5b60006020828403121561348857600080fd5b8135610fbd81613460565b6000602082840312156134a557600080fd5b5035919050565b60005b838110156134c75781810151838201526020016134af565b50506000910152565b600081518084526134e88160208601602086016134ac565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134d0565b6000806040838503121561352257600080fd5b823561352d8161341b565b946020939093013593505050565b6000806040838503121561354e57600080fd5b50508035926020909101359150565b60008060006060848603121561357257600080fd5b833561357d8161341b565b9250602084013561358d8161341b565b929592945050506040919091013590565b80356001600160a01b0319811681146135b657600080fd5b919050565b600080604083850312156135ce57600080fd5b823591506135de6020840161359e565b90509250929050565b60008083601f8401126135f957600080fd5b5081356001600160401b0381111561361057600080fd5b6020830191508360208260051b850101111561362b57600080fd5b9250929050565b6000806020838503121561364557600080fd5b82356001600160401b0381111561365b57600080fd5b613667858286016135e7565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136ef57888603603f19018552825180518088529088019088880190845b818110156136d95783518352928a0192918a01916001016136bd565b509097505050938601939186019160010161369b565b509398975050505050505050565b60008060006040848603121561371257600080fd5b83356001600160401b0381111561372857600080fd5b613734868287016135e7565b909790965060209590950135949350505050565b60006020828403121561375a57600080fd5b8135610fbd8161341b565b602080825282518282018190526000919060409081850190868401855b828110156137b15781518051855286810151878601528501518585015260609093019290850190600101613782565b5091979650505050505050565b600080604083850312156137d157600080fd5b82356137dc8161341b565b91506020830135801515811461345557600080fd5b60008060006040848603121561380657600080fd5b83356001600160401b0381111561381c57600080fd5b613828868287016135e7565b909450925061383b90506020850161359e565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561388257613882613844565b604052919050565b600080600080608085870312156138a057600080fd5b84356138ab8161341b565b93506020858101356138bc8161341b565b93506040860135925060608601356001600160401b03808211156138df57600080fd5b818801915088601f8301126138f357600080fd5b81358181111561390557613905613844565b613917601f8201601f1916850161385a565b9150808252898482850101111561392d57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561396257600080fd5b83356001600160401b0381111561397857600080fd5b613984868287016135e7565b90945092505060208401356139988161341b565b809150509250925092565b600080600080608085870312156139b957600080fd5b84359350602085013592506139d06040860161359e565b9396929550929360600135925050565b6000806000606084860312156139f557600080fd5b83359250602080850135925060408501356001600160401b0380821115613a1b57600080fd5b818701915087601f830112613a2f57600080fd5b813581811115613a4157613a41613844565b8060051b9150613a5284830161385a565b818152918301840191848101908a841115613a6c57600080fd5b938501935b83851015613a9157613a828561359e565b82529385019390850190613a71565b8096505050505050509250925092565b60008060408385031215613ab457600080fd5b8235613abf8161341b565b915060208301356134558161341b565b600181811c90821680613ae357607f821691505b602082108103613b0357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b7e57600080fd5b610fbd8261359e565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613ba9565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b60006001600160fb1b03831115613c3f57600080fd5b8260051b80858437919091019392505050565b60008351613c648184602088016134ac565b835190830190613c788183602088016134ac565b01949350505050565b80820281158282048414176109cf576109cf613ba9565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d62908301846134d0565b9695505050505050565b600060208284031215613d7e57600080fd5b8151610fbd8161346056fea2646970667358221220f2bdba1caf01add5d9d0c859f09b34e6be24ec98d778f8a9cf110ac34053fb0664736f6c63430008130033` + _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc980620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341d565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613463565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613480565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134e9565b34801561034a57600080fd5b5061035e610359366004613480565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fc565b610ab4565b3480156103a257600080fd5b506102b76103b1366004613528565b610bc9565b3480156103c257600080fd5b506102b76103d136600461354a565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135a8565b610c6d565b34801561040257600080fd5b506102b7610411366004613480565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b61044636600461361f565b610d9c565b6040516102e59190613660565b34801561046457600080fd5b506102b761047336600461354a565b610f18565b34801561048457600080fd5b50610498610493366004613480565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613528565b610fa9565b61030e6104f83660046135a8565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136ea565b61103a565b34801561054857600080fd5b506102b761055736600461361f565b6110e1565b34801561056857600080fd5b506102b7610577366004613480565b611177565b34801561058857600080fd5b5061035e610597366004613480565b6111d9565b3480156105a857600080fd5b5061044b6105b736600461361f565b611239565b3480156105c857600080fd5b5061030e6105d7366004613735565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c366004613528565b611445565b6040516102e59190613752565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613480565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137ab565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137de565b6115d3565b6102b76106e9366004613528565b61166a565b3480156106fa57600080fd5b506102b7610709366004613877565b611772565b34801561071a57600080fd5b506102b761072936600461393a565b6117aa565b6102b761073c3660046136ea565b611899565b34801561074d57600080fd5b5061033161075c366004613480565b611aa0565b34801561076d57600080fd5b506102b761077c366004613528565b611b13565b61030e61078f366004613990565b611cb8565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613528565b611d82565b61030e6107d83660046139cd565b611e6b565b3480156107e957600080fd5b506102b76107f8366004613528565b611f5d565b34801561080957600080fd5b506102b761081836600461361f565b611fd1565b34801561082957600080fd5b506102d9610838366004613a8e565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613528565b6120ad565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613735565b612123565b6108c461219c565b816108ce816121e9565b600083815260086020526040902060028101546108ea9061223e565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122b3565b6109478184612356565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612415565b6000828152600860205260409020600201546109cf9061223e565b606060008054610a0a90613abc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613abc565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612415565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612474565b505050565b610bd161219c565b81610bdb816121e9565b6000838152600860205260409020610bf2816124e2565b610bfc818461252c565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612614565b610c625760405162461bcd60e51b815260040161092b90613af6565b610bc4838383612692565b610c7561219c565b81610c7f816121e9565b6000838152600860205260409020610c979083612803565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce361219c565b80610ced816121e9565b6000828152600860205260409020610d04816124e2565b610d0d81612906565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129e6565b610d9a612a40565b565b6060816001600160401b03811115610db657610db6613831565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613831565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b43565b6020026020010181905250600060096000878785818110610e7b57610e7b613b43565b9050602002016020810190610e909190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b43565b60200260200101518281518110610ef357610ef3613b43565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612415565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b43565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612a95565b612afc565b9392505050565b6000610fce61219c565b346000610fdb8286612a95565b9050610fe681612b2d565b610ff08185612b79565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b74565b60405180910390a295945050505050565b61104261219c565b60008060005b848110156110d95785858281811061106257611062613b43565b905060200201359250611074836121e9565b6000838152600860205260409020915061108d826124e2565b611097828561252c565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e961219c565b60008060005b838110156111705784848281811061110957611109613b43565b90506020020135925061111b836121e9565b6000838152600860205260409020915061113482612c19565b61113d82612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f61219c565b80611189816121e9565b60008281526008602052604090206111a081612c19565b6111a981612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613831565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613831565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b43565b60200260200101819052506000600a600087878581811061131857611318613b43565b905060200201602081019061132d9190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b43565b6020026020010151828151811061139057611390613b43565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129e6565b610d9a6000612cbb565b60606000821180156114625750600b5461145f8385613bac565b11155b61147e5760405162461bcd60e51b815260040161092b90613bbf565b816001600160401b0381111561149657611496613831565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b43565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b43565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129e6565b610d9a612d0d565b600061159582612415565b60008281526008602052604090206115ac816124e2565b610fbd81612906565b606060018054610a0a90613abc565b6115cf338383612d50565b5050565b6115db61219c565b6000805b83811015611170578484828181106115f9576115f9613b43565b90506020020135915061160b826121e9565b60008281526008602052604090206116239084612803565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b61167261219c565b8161167c816121e9565b600083815260086020526040902061169381612c19565b8054600b805460009190839081106116ad576116ad613b43565b90600052602060002090600302019050848160000154346116ce9190613bac565b146116eb5760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e1e565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612614565b6117985760405162461bcd60e51b815260040161092b90613af6565b6117a484848484612e6e565b50505050565b6117b261219c565b60008060005b848110156110d9578585828181106117d2576117d2613b43565b9050602002013592506117e4836121e9565b600083815260086020526040902060028101549092506118039061223e565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122b3565b61185b8285612356565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a161219c565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611a96576000190187878281811061190557611905613b43565b905060200201359350611917846121e9565b60008481526008602052604090209250611930836124e2565b82546003840154600b805460a09290921b918390811061195257611952613b43565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bac565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122b3565b611a8f565b6000196001860155611a5185888a612e1e565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a869493929190613c16565b60405180910390a15b50506118e9565b5050505050505050565b6060611aab82612415565b6000611ac260408051602081019091526000815290565b90506000815111611ae25760405180602001604052806000815250610fbd565b80611aec84612ea1565b604051602001611afd929190613c5c565b6040516020818303038152906040529392505050565b611b1b6129e6565b81600003611b5f5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bbe5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc261219c565b600082118015611cda575034611cd88387613c8b565b145b611cf65760405162461bcd60e51b815260040161092b90613bbf565b6000611d028686612a95565b9050611d0d81612b2d565b600754600101915060005b83811015611d7757611d2a8286612b79565b611d348184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6793929190613b74565b60405180910390a2600101611d18565b50505b949350505050565b611d8a61219c565b81611d94816121e9565b6000838152600860205260409020611dab81612c19565b8054600b80546000919083908110611dc557611dc5613b43565b9060005260206000209060030201905080600101548511611df85760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3990849087612e1e565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e7561219c565b34825185611e839190613c8b565b14611ea05760405162461bcd60e51b815260040161092b90613bbf565b6000611eac8585612a95565b9050611eb781612b2d565b600754600101915060005b8351811015611f5457611eee82858381518110611ee157611ee1613b43565b6020026020010151612b79565b611ef88184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2b57611f2b613b43565b60200260200101518888604051611f4493929190613b74565b60405180910390a2600101611ec2565b50509392505050565b611f656129e6565b43600b611f728484612a95565b81548110611f8257611f82613b43565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cac929190918252602082015260400190565b611fd961219c565b60008060005b8381101561117057848482818110611ff957611ff9613b43565b90506020020135925061200b836121e9565b60008381526008602052604090209150612024826124e2565b61202d82612906565b156120715760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61207a826129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fdf565b6120b56129e6565b600019600b6120c48484612a95565b815481106120d4576120d4613b43565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cac929190918252602082015260400190565b61212b6129e6565b6001600160a01b0381166121905760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b61219981612cbb565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b6121f2816111d9565b6001600160a01b0316336001600160a01b0316146121995760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361228a5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b600061229861ca8084613bac565b90504381116122aa5750600092915050565b43900392915050565b60006122be826111d9565b90506122ce816000846001612f33565b6122d7826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236f5761236f613b43565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123ca576040519150601f19603f3d011682016040523d82523d6000602084013e6123cf565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121995760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a9826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61253f84612906565b8310156125815760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125b1600b848154811061259957612599613b43565b90600052602060002090600302016000015485612a95565b90506125bc81612b2d565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612620836111d9565b9050806001600160a01b0316846001600160a01b0316148061266757506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d7a5750836001600160a01b031661268084610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126a5826111d9565b6001600160a01b0316146126cb5760405162461bcd60e51b815260040161092b90613ca2565b6001600160a01b03821661272d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61273a8383836001612f33565b826001600160a01b031661274d826111d9565b6001600160a01b0316146127735760405162461bcd60e51b815260040161092b90613ca2565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280c826124e2565b8154600383015460a01b6001600160a01b0319808416908216036128425760405162461bcd60e51b815260040161092b90613beb565b600184015460001914612899576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128df565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129585760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061297157612971613b43565b9060005260206000209060030201600101548261298e9190613bac565b90504381116129a1575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a48612ffc565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af25760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d7a565b600043600b8381548110612b1257612b12613b43565b90600052602060002090600302016002015411159050919050565b612b3681612afc565b6121995760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061304c565b6001810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1561219c565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a783390565b816001600160a01b0316836001600160a01b031603612db15760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e2a8383612a95565b9050612e3581612b2d565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e79848484612692565b612e8584848484613066565b6117a45760405162461bcd60e51b815260040161092b90613ce7565b60606000612eae83613164565b60010190506000816001600160401b03811115612ecd57612ecd613831565b6040519080825280601f01601f191660200182016040528015612ef7576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f0157509392505050565b80600114612f835760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fab5750600082815260086020526040902060020154600019145b612ff75760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061323c565b60006001600160a01b0384163b1561315c57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130aa903390899088908890600401613d39565b6020604051808303816000875af19250505080156130e5575060408051601f3d908101601f191682019092526130e291810190613d76565b60015b613142573d808015613113576040519150601f19603f3d011682016040523d82523d6000602084013e613118565b606091505b50805160000361313a5760405162461bcd60e51b815260040161092b90613ce7565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d7a565b506001611d7a565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a35772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cf576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131ed57662386f26fc10000830492506010015b6305f5e1008310613205576305f5e100830492506008015b612710831061321957612710830492506004015b6064831061322b576064830492506002015b600a83106109cf5760010192915050565b613246838361326f565b6132536000848484613066565b610bc45760405162461bcd60e51b815260040161092b90613ce7565b6001600160a01b0382166132c55760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561332a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b613338600083836001612f33565b6000818152600260205260409020546001600160a01b03161561339d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219957600080fd5b6000806040838503121561343057600080fd5b82359150602083013561344281613408565b809150509250929050565b6001600160e01b03198116811461219957600080fd5b60006020828403121561347557600080fd5b8135610fbd8161344d565b60006020828403121561349257600080fd5b5035919050565b60005b838110156134b457818101518382015260200161349c565b50506000910152565b600081518084526134d5816020860160208601613499565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134bd565b6000806040838503121561350f57600080fd5b823561351a81613408565b946020939093013593505050565b6000806040838503121561353b57600080fd5b50508035926020909101359150565b60008060006060848603121561355f57600080fd5b833561356a81613408565b9250602084013561357a81613408565b929592945050506040919091013590565b80356001600160a01b0319811681146135a357600080fd5b919050565b600080604083850312156135bb57600080fd5b823591506135cb6020840161358b565b90509250929050565b60008083601f8401126135e657600080fd5b5081356001600160401b038111156135fd57600080fd5b6020830191508360208260051b850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b82356001600160401b0381111561364857600080fd5b613654858286016135d4565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136dc57888603603f19018552825180518088529088019088880190845b818110156136c65783518352928a0192918a01916001016136aa565b5090975050509386019391860191600101613688565b509398975050505050505050565b6000806000604084860312156136ff57600080fd5b83356001600160401b0381111561371557600080fd5b613721868287016135d4565b909790965060209590950135949350505050565b60006020828403121561374757600080fd5b8135610fbd81613408565b602080825282518282018190526000919060409081850190868401855b8281101561379e578151805185528681015187860152850151858501526060909301929085019060010161376f565b5091979650505050505050565b600080604083850312156137be57600080fd5b82356137c981613408565b91506020830135801515811461344257600080fd5b6000806000604084860312156137f357600080fd5b83356001600160401b0381111561380957600080fd5b613815868287016135d4565b909450925061382890506020850161358b565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386f5761386f613831565b604052919050565b6000806000806080858703121561388d57600080fd5b843561389881613408565b93506020858101356138a981613408565b93506040860135925060608601356001600160401b03808211156138cc57600080fd5b818801915088601f8301126138e057600080fd5b8135818111156138f2576138f2613831565b613904601f8201601f19168501613847565b9150808252898482850101111561391a57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394f57600080fd5b83356001600160401b0381111561396557600080fd5b613971868287016135d4565b909450925050602084013561398581613408565b809150509250925092565b600080600080608085870312156139a657600080fd5b84359350602085013592506139bd6040860161358b565b9396929550929360600135925050565b6000806000606084860312156139e257600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0857600080fd5b818701915087601f830112613a1c57600080fd5b813581811115613a2e57613a2e613831565b8060051b9150613a3f848301613847565b818152918301840191848101908a841115613a5957600080fd5b938501935b83851015613a7e57613a6f8561358b565b82529385019390850190613a5e565b8096505050505050509250925092565b60008060408385031215613aa157600080fd5b8235613aac81613408565b9150602083013561344281613408565b600181811c90821680613ad057607f821691505b602082108103613af057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6b57600080fd5b610fbd8261358b565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613b96565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3657600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6e818460208801613499565b835190830190613c82818360208801613499565b01949350505050565b80820281158282048414176109cf576109cf613b96565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6c908301846134bd565b9695505050505050565b600060208284031215613d8857600080fd5b8151610fbd8161344d56fea2646970667358221220838d751ed1580567aada864b691317738d1db46809b8ca2091226ee62191d65464736f6c63430008130033` ) func TestLiquidStaking(t *testing.T) { @@ -119,6 +120,9 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) buckets, err := indexer.GetBuckets() r.NoError(err) + slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + return i.Index < j.Index + }) bt := buckets[len(buckets)-1] tokenID := bt.Index r.EqualValues(1, bt.Index) @@ -190,10 +194,10 @@ func TestLiquidStaking(t *testing.T) { } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) - r.EqualValues("", receipts[0].ExecutionRevertMsg()) - r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) - r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) + // r.EqualValues("", receipts[0].ExecutionRevertMsg()) + // r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + // bt, err = indexer.GetBucket(uint64(tokenID)) + // r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) }) }) }) @@ -262,6 +266,9 @@ func TestLiquidStaking(t *testing.T) { } buckets, err := indexer.GetBuckets() r.NoError(err) + slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + return i.Index < j.Index + }) r.True(len(buckets) >= 10) // merge newBuckets := buckets[len(buckets)-10:] @@ -281,7 +288,18 @@ func TestLiquidStaking(t *testing.T) { } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + for i := range newBuckets { + if i == 0 { + bt, err := indexer.GetBucket(uint64(newBuckets[i].Index)) + r.NoError(err) + r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) + } else { + _, err := indexer.GetBucket(uint64(newBuckets[i].Index)) + r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) + } + } }) t.Run("extend duration", func(t *testing.T) { @@ -590,6 +608,9 @@ func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blo r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) buckets, err := indexer.GetBuckets() r.NoError(err) + slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + return i.Index < j.Index + }) bt := buckets[len(buckets)-1] return bt } From 6438929f5adde9ae83f8f9c1adbad5d6a9a3d22b Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 28 Apr 2023 10:31:37 +0800 Subject: [PATCH 20/51] add withdraw test --- .../execution/testdata/system-staking.json | 8 ++++---- .../protocol/execution/testdata/system-staking.sol | 2 +- e2etest/liquid_staking_test.go | 14 ++++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/action/protocol/execution/testdata/system-staking.json b/action/protocol/execution/testdata/system-staking.json index 20c525ee31..8b3672621b 100644 --- a/action/protocol/execution/testdata/system-staking.json +++ b/action/protocol/execution/testdata/system-staking.json @@ -11,12 +11,12 @@ ], "deployments":[ { - "rawByteCode": "60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b2366004613430565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613476565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613493565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134fc565b34801561034a57600080fd5b5061035e610359366004613493565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b761039136600461350f565b610ab4565b3480156103a257600080fd5b506102b76103b136600461353b565b610bc9565b3480156103c257600080fd5b506102b76103d136600461355d565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135bb565b610c6d565b34801561040257600080fd5b506102b7610411366004613493565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b610446366004613632565b610d9c565b6040516102e59190613673565b34801561046457600080fd5b506102b761047336600461355d565b610f18565b34801561048457600080fd5b50610498610493366004613493565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e536600461353b565b610fa9565b61030e6104f83660046135bb565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136fd565b61103a565b34801561054857600080fd5b506102b7610557366004613632565b6110e1565b34801561056857600080fd5b506102b7610577366004613493565b611177565b34801561058857600080fd5b5061035e610597366004613493565b6111d9565b3480156105a857600080fd5b5061044b6105b7366004613632565b611239565b3480156105c857600080fd5b5061030e6105d7366004613748565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c36600461353b565b611445565b6040516102e59190613765565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613493565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137be565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137f1565b6115d3565b6102b76106e936600461353b565b61166a565b3480156106fa57600080fd5b506102b761070936600461388a565b611772565b34801561071a57600080fd5b506102b761072936600461394d565b6117aa565b6102b761073c3660046136fd565b611899565b34801561074d57600080fd5b5061033161075c366004613493565b611ab3565b34801561076d57600080fd5b506102b761077c36600461353b565b611b26565b61030e61078f3660046139a3565b611ccb565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c536600461353b565b611d95565b61030e6107d83660046139e0565b611e7e565b3480156107e957600080fd5b506102b76107f836600461353b565b611f70565b34801561080957600080fd5b506102b7610818366004613632565b611fe4565b34801561082957600080fd5b506102d9610838366004613aa1565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b761088136600461353b565b6120c0565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613748565b612136565b6108c46121af565b816108ce816121fc565b600083815260086020526040902060028101546108ea90612251565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122c6565b6109478184612369565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612428565b6000828152600860205260409020600201546109cf90612251565b606060008054610a0a90613acf565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613acf565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612428565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612487565b505050565b610bd16121af565b81610bdb816121fc565b6000838152600860205260409020610bf2816124f5565b610bfc818461253f565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612627565b610c625760405162461bcd60e51b815260040161092b90613b09565b610bc48383836126a5565b610c756121af565b81610c7f816121fc565b6000838152600860205260409020610c979083612816565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce36121af565b80610ced816121fc565b6000828152600860205260409020610d04816124f5565b610d0d81612919565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129f9565b610d9a612a53565b565b6060816001600160401b03811115610db657610db6613844565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613844565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b56565b6020026020010181905250600060096000878785818110610e7b57610e7b613b56565b9050602002016020810190610e909190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b56565b60200260200101518281518110610ef357610ef3613b56565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612428565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b56565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612aa8565b612b0f565b9392505050565b6000610fce6121af565b346000610fdb8286612aa8565b9050610fe681612b40565b610ff08185612b8c565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b87565b60405180910390a295945050505050565b6110426121af565b60008060005b848110156110d95785858281811061106257611062613b56565b905060200201359250611074836121fc565b6000838152600860205260409020915061108d826124f5565b611097828561253f565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e96121af565b60008060005b838110156111705784848281811061110957611109613b56565b90506020020135925061111b836121fc565b6000838152600860205260409020915061113482612c2c565b61113d82612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f6121af565b80611189816121fc565b60008281526008602052604090206111a081612c2c565b6111a981612c76565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613844565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613844565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b56565b60200260200101819052506000600a600087878581811061131857611318613b56565b905060200201602081019061132d9190613b6c565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b56565b6020026020010151828151811061139057611390613b56565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129f9565b610d9a6000612cce565b60606000821180156114625750600b5461145f8385613bbf565b11155b61147e5760405162461bcd60e51b815260040161092b90613bd2565b816001600160401b0381111561149657611496613844565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b56565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b56565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129f9565b610d9a612d20565b600061159582612428565b60008281526008602052604090206115ac816124f5565b610fbd81612919565b606060018054610a0a90613acf565b6115cf338383612d63565b5050565b6115db6121af565b6000805b83811015611170578484828181106115f9576115f9613b56565b90506020020135915061160b826121fc565b60008281526008602052604090206116239084612816565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b6116726121af565b8161167c816121fc565b600083815260086020526040902061169381612c2c565b8054600b805460009190839081106116ad576116ad613b56565b90600052602060002090600302019050848160000154346116ce9190613bbf565b146116eb5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e31565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612627565b6117985760405162461bcd60e51b815260040161092b90613b09565b6117a484848484612e81565b50505050565b6117b26121af565b60008060005b848110156110d9578585828181106117d2576117d2613b56565b9050602002013592506117e4836121fc565b6000838152600860205260409020600281015490925061180390612251565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122c6565b61185b8285612369565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a16121af565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611aa9576000190187878281811061190557611905613b56565b905060200201359350611917846121fc565b60008481526008602052604090209250611930836124f5565b82546003840154600b805460a09290921b918390811061195257611952613b56565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bbf565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122c6565b611aa2565b6000196001860155611a5185888a612e31565b8989604051611a61929190613c29565b60408051918290038220898352602083018b9052917fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b12910160405180910390a25b50506118e9565b5050505050505050565b6060611abe82612428565b6000611ad560408051602081019091526000815290565b90506000815111611af55760405180602001604052806000815250610fbd565b80611aff84612eb4565b604051602001611b10929190613c52565b6040516020818303038152906040529392505050565b611b2e6129f9565b81600003611b725760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bd15760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cd56121af565b600082118015611ced575034611ceb8387613c81565b145b611d095760405162461bcd60e51b815260040161092b90613bd2565b6000611d158686612aa8565b9050611d2081612b40565b600754600101915060005b83811015611d8a57611d3d8286612b8c565b611d478184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d7a93929190613b87565b60405180910390a2600101611d2b565b50505b949350505050565b611d9d6121af565b81611da7816121fc565b6000838152600860205260409020611dbe81612c2c565b8054600b80546000919083908110611dd857611dd8613b56565b9060005260206000209060030201905080600101548511611e0b5760405162461bcd60e51b815260040161092b90613bfe565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e4c90849087612e31565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e886121af565b34825185611e969190613c81565b14611eb35760405162461bcd60e51b815260040161092b90613bd2565b6000611ebf8585612aa8565b9050611eca81612b40565b600754600101915060005b8351811015611f6757611f0182858381518110611ef457611ef4613b56565b6020026020010151612b8c565b611f0b8184613bbf565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f3e57611f3e613b56565b60200260200101518888604051611f5793929190613b87565b60405180910390a2600101611ed5565b50509392505050565b611f786129f9565b43600b611f858484612aa8565b81548110611f9557611f95613b56565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cbf929190918252602082015260400190565b611fec6121af565b60008060005b838110156111705784848281811061200c5761200c613b56565b90506020020135925061201e836121fc565b60008381526008602052604090209150612037826124f5565b61204082612919565b156120845760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61208d826129be565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611ff2565b6120c86129f9565b600019600b6120d78484612aa8565b815481106120e7576120e7613b56565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cbf929190918252602082015260400190565b61213e6129f9565b6001600160a01b0381166121a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b6121ac81612cce565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b612205816111d9565b6001600160a01b0316336001600160a01b0316146121ac5760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361229d5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b60006122ab61ca8084613bbf565b90504381116122bd5750600092915050565b43900392915050565b60006122d1826111d9565b90506122e1816000846001612f46565b6122ea826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061238257612382613b56565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121ac5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124bc826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61255284612919565b8310156125945760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125c4600b84815481106125ac576125ac613b56565b90600052602060002090600302016000015485612aa8565b90506125cf81612b40565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612633836111d9565b9050806001600160a01b0316846001600160a01b0316148061267a57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d8d5750836001600160a01b031661269384610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126b8826111d9565b6001600160a01b0316146126de5760405162461bcd60e51b815260040161092b90613c98565b6001600160a01b0382166127405760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61274d8383836001612f46565b826001600160a01b0316612760826111d9565b6001600160a01b0316146127865760405162461bcd60e51b815260040161092b90613c98565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61281f826124f5565b8154600383015460a01b6001600160a01b0319808416908216036128555760405162461bcd60e51b815260040161092b90613bfe565b6001840154600019146128ac576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128f2565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b6001810154600090600019810361296b5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061298457612984613b56565b906000526020600020906003020160010154826129a19190613bbf565b90504381116129b4575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a5b61300f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b055760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d8d565b600043600b8381548110612b2557612b25613b56565b90600052602060002090600302016002015411159050919050565b612b4981612b0f565b6121ac5760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061305f565b6001810154600019146121ac5760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d286121af565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a8b3390565b816001600160a01b0316836001600160a01b031603612dc45760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e3d8383612aa8565b9050612e4881612b40565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e8c8484846126a5565b612e9884848484613079565b6117a45760405162461bcd60e51b815260040161092b90613cdd565b60606000612ec183613177565b60010190506000816001600160401b03811115612ee057612ee0613844565b6040519080825280601f01601f191660200182016040528015612f0a576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f1457509392505050565b80600114612f965760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fbe5750600082815260086020526040902060020154600019145b61300a5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061324f565b60006001600160a01b0384163b1561316f57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130bd903390899088908890600401613d2f565b6020604051808303816000875af19250505080156130f8575060408051601f3d908101601f191682019092526130f591810190613d6c565b60015b613155573d808015613126576040519150601f19603f3d011682016040523d82523d6000602084013e61312b565b606091505b50805160000361314d5760405162461bcd60e51b815260040161092b90613cdd565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d8d565b506001611d8d565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131b65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131e2576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061320057662386f26fc10000830492506010015b6305f5e1008310613218576305f5e100830492506008015b612710831061322c57612710830492506004015b6064831061323e576064830492506002015b600a83106109cf5760010192915050565b6132598383613282565b6132666000848484613079565b610bc45760405162461bcd60e51b815260040161092b90613cdd565b6001600160a01b0382166132d85760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561333d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b61334b600083836001612f46565b6000818152600260205260409020546001600160a01b0316156133b05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121ac57600080fd5b6000806040838503121561344357600080fd5b8235915060208301356134558161341b565b809150509250929050565b6001600160e01b0319811681146121ac57600080fd5b60006020828403121561348857600080fd5b8135610fbd81613460565b6000602082840312156134a557600080fd5b5035919050565b60005b838110156134c75781810151838201526020016134af565b50506000910152565b600081518084526134e88160208601602086016134ac565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134d0565b6000806040838503121561352257600080fd5b823561352d8161341b565b946020939093013593505050565b6000806040838503121561354e57600080fd5b50508035926020909101359150565b60008060006060848603121561357257600080fd5b833561357d8161341b565b9250602084013561358d8161341b565b929592945050506040919091013590565b80356001600160a01b0319811681146135b657600080fd5b919050565b600080604083850312156135ce57600080fd5b823591506135de6020840161359e565b90509250929050565b60008083601f8401126135f957600080fd5b5081356001600160401b0381111561361057600080fd5b6020830191508360208260051b850101111561362b57600080fd5b9250929050565b6000806020838503121561364557600080fd5b82356001600160401b0381111561365b57600080fd5b613667858286016135e7565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136ef57888603603f19018552825180518088529088019088880190845b818110156136d95783518352928a0192918a01916001016136bd565b509097505050938601939186019160010161369b565b509398975050505050505050565b60008060006040848603121561371257600080fd5b83356001600160401b0381111561372857600080fd5b613734868287016135e7565b909790965060209590950135949350505050565b60006020828403121561375a57600080fd5b8135610fbd8161341b565b602080825282518282018190526000919060409081850190868401855b828110156137b15781518051855286810151878601528501518585015260609093019290850190600101613782565b5091979650505050505050565b600080604083850312156137d157600080fd5b82356137dc8161341b565b91506020830135801515811461345557600080fd5b60008060006040848603121561380657600080fd5b83356001600160401b0381111561381c57600080fd5b613828868287016135e7565b909450925061383b90506020850161359e565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561388257613882613844565b604052919050565b600080600080608085870312156138a057600080fd5b84356138ab8161341b565b93506020858101356138bc8161341b565b93506040860135925060608601356001600160401b03808211156138df57600080fd5b818801915088601f8301126138f357600080fd5b81358181111561390557613905613844565b613917601f8201601f1916850161385a565b9150808252898482850101111561392d57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561396257600080fd5b83356001600160401b0381111561397857600080fd5b613984868287016135e7565b90945092505060208401356139988161341b565b809150509250925092565b600080600080608085870312156139b957600080fd5b84359350602085013592506139d06040860161359e565b9396929550929360600135925050565b6000806000606084860312156139f557600080fd5b83359250602080850135925060408501356001600160401b0380821115613a1b57600080fd5b818701915087601f830112613a2f57600080fd5b813581811115613a4157613a41613844565b8060051b9150613a5284830161385a565b818152918301840191848101908a841115613a6c57600080fd5b938501935b83851015613a9157613a828561359e565b82529385019390850190613a71565b8096505050505050509250925092565b60008060408385031215613ab457600080fd5b8235613abf8161341b565b915060208301356134558161341b565b600181811c90821680613ae357607f821691505b602082108103613b0357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b7e57600080fd5b610fbd8261359e565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613ba9565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b60006001600160fb1b03831115613c3f57600080fd5b8260051b80858437919091019392505050565b60008351613c648184602088016134ac565b835190830190613c788183602088016134ac565b01949350505050565b80820281158282048414176109cf576109cf613ba9565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d62908301846134d0565b9695505050505050565b600060208284031215613d7e57600080fd5b8151610fbd8161346056fea2646970667358221220f2bdba1caf01add5d9d0c859f09b34e6be24ec98d778f8a9cf110ac34053fb0664736f6c63430008130033", + "rawByteCode": "60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc980620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341d565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613463565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613480565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134e9565b34801561034a57600080fd5b5061035e610359366004613480565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fc565b610ab4565b3480156103a257600080fd5b506102b76103b1366004613528565b610bc9565b3480156103c257600080fd5b506102b76103d136600461354a565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135a8565b610c6d565b34801561040257600080fd5b506102b7610411366004613480565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b61044636600461361f565b610d9c565b6040516102e59190613660565b34801561046457600080fd5b506102b761047336600461354a565b610f18565b34801561048457600080fd5b50610498610493366004613480565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613528565b610fa9565b61030e6104f83660046135a8565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136ea565b61103a565b34801561054857600080fd5b506102b761055736600461361f565b6110e1565b34801561056857600080fd5b506102b7610577366004613480565b611177565b34801561058857600080fd5b5061035e610597366004613480565b6111d9565b3480156105a857600080fd5b5061044b6105b736600461361f565b611239565b3480156105c857600080fd5b5061030e6105d7366004613735565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c366004613528565b611445565b6040516102e59190613752565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613480565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137ab565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137de565b6115d3565b6102b76106e9366004613528565b61166a565b3480156106fa57600080fd5b506102b7610709366004613877565b611772565b34801561071a57600080fd5b506102b761072936600461393a565b6117aa565b6102b761073c3660046136ea565b611899565b34801561074d57600080fd5b5061033161075c366004613480565b611aa0565b34801561076d57600080fd5b506102b761077c366004613528565b611b13565b61030e61078f366004613990565b611cb8565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613528565b611d82565b61030e6107d83660046139cd565b611e6b565b3480156107e957600080fd5b506102b76107f8366004613528565b611f5d565b34801561080957600080fd5b506102b761081836600461361f565b611fd1565b34801561082957600080fd5b506102d9610838366004613a8e565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613528565b6120ad565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613735565b612123565b6108c461219c565b816108ce816121e9565b600083815260086020526040902060028101546108ea9061223e565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122b3565b6109478184612356565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612415565b6000828152600860205260409020600201546109cf9061223e565b606060008054610a0a90613abc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613abc565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612415565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612474565b505050565b610bd161219c565b81610bdb816121e9565b6000838152600860205260409020610bf2816124e2565b610bfc818461252c565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612614565b610c625760405162461bcd60e51b815260040161092b90613af6565b610bc4838383612692565b610c7561219c565b81610c7f816121e9565b6000838152600860205260409020610c979083612803565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce361219c565b80610ced816121e9565b6000828152600860205260409020610d04816124e2565b610d0d81612906565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129e6565b610d9a612a40565b565b6060816001600160401b03811115610db657610db6613831565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613831565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b43565b6020026020010181905250600060096000878785818110610e7b57610e7b613b43565b9050602002016020810190610e909190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b43565b60200260200101518281518110610ef357610ef3613b43565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612415565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b43565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612a95565b612afc565b9392505050565b6000610fce61219c565b346000610fdb8286612a95565b9050610fe681612b2d565b610ff08185612b79565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b74565b60405180910390a295945050505050565b61104261219c565b60008060005b848110156110d95785858281811061106257611062613b43565b905060200201359250611074836121e9565b6000838152600860205260409020915061108d826124e2565b611097828561252c565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e961219c565b60008060005b838110156111705784848281811061110957611109613b43565b90506020020135925061111b836121e9565b6000838152600860205260409020915061113482612c19565b61113d82612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f61219c565b80611189816121e9565b60008281526008602052604090206111a081612c19565b6111a981612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613831565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613831565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b43565b60200260200101819052506000600a600087878581811061131857611318613b43565b905060200201602081019061132d9190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b43565b6020026020010151828151811061139057611390613b43565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129e6565b610d9a6000612cbb565b60606000821180156114625750600b5461145f8385613bac565b11155b61147e5760405162461bcd60e51b815260040161092b90613bbf565b816001600160401b0381111561149657611496613831565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b43565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b43565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129e6565b610d9a612d0d565b600061159582612415565b60008281526008602052604090206115ac816124e2565b610fbd81612906565b606060018054610a0a90613abc565b6115cf338383612d50565b5050565b6115db61219c565b6000805b83811015611170578484828181106115f9576115f9613b43565b90506020020135915061160b826121e9565b60008281526008602052604090206116239084612803565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b61167261219c565b8161167c816121e9565b600083815260086020526040902061169381612c19565b8054600b805460009190839081106116ad576116ad613b43565b90600052602060002090600302019050848160000154346116ce9190613bac565b146116eb5760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e1e565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612614565b6117985760405162461bcd60e51b815260040161092b90613af6565b6117a484848484612e6e565b50505050565b6117b261219c565b60008060005b848110156110d9578585828181106117d2576117d2613b43565b9050602002013592506117e4836121e9565b600083815260086020526040902060028101549092506118039061223e565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122b3565b61185b8285612356565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a161219c565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611a96576000190187878281811061190557611905613b43565b905060200201359350611917846121e9565b60008481526008602052604090209250611930836124e2565b82546003840154600b805460a09290921b918390811061195257611952613b43565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bac565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122b3565b611a8f565b6000196001860155611a5185888a612e1e565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a869493929190613c16565b60405180910390a15b50506118e9565b5050505050505050565b6060611aab82612415565b6000611ac260408051602081019091526000815290565b90506000815111611ae25760405180602001604052806000815250610fbd565b80611aec84612ea1565b604051602001611afd929190613c5c565b6040516020818303038152906040529392505050565b611b1b6129e6565b81600003611b5f5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bbe5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc261219c565b600082118015611cda575034611cd88387613c8b565b145b611cf65760405162461bcd60e51b815260040161092b90613bbf565b6000611d028686612a95565b9050611d0d81612b2d565b600754600101915060005b83811015611d7757611d2a8286612b79565b611d348184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6793929190613b74565b60405180910390a2600101611d18565b50505b949350505050565b611d8a61219c565b81611d94816121e9565b6000838152600860205260409020611dab81612c19565b8054600b80546000919083908110611dc557611dc5613b43565b9060005260206000209060030201905080600101548511611df85760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3990849087612e1e565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e7561219c565b34825185611e839190613c8b565b14611ea05760405162461bcd60e51b815260040161092b90613bbf565b6000611eac8585612a95565b9050611eb781612b2d565b600754600101915060005b8351811015611f5457611eee82858381518110611ee157611ee1613b43565b6020026020010151612b79565b611ef88184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2b57611f2b613b43565b60200260200101518888604051611f4493929190613b74565b60405180910390a2600101611ec2565b50509392505050565b611f656129e6565b43600b611f728484612a95565b81548110611f8257611f82613b43565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cac929190918252602082015260400190565b611fd961219c565b60008060005b8381101561117057848482818110611ff957611ff9613b43565b90506020020135925061200b836121e9565b60008381526008602052604090209150612024826124e2565b61202d82612906565b156120715760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61207a826129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fdf565b6120b56129e6565b600019600b6120c48484612a95565b815481106120d4576120d4613b43565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cac929190918252602082015260400190565b61212b6129e6565b6001600160a01b0381166121905760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b61219981612cbb565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b6121f2816111d9565b6001600160a01b0316336001600160a01b0316146121995760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361228a5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b600061229861ca8084613bac565b90504381116122aa5750600092915050565b43900392915050565b60006122be826111d9565b90506122ce816000846001612f33565b6122d7826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236f5761236f613b43565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123ca576040519150601f19603f3d011682016040523d82523d6000602084013e6123cf565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121995760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a9826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61253f84612906565b8310156125815760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125b1600b848154811061259957612599613b43565b90600052602060002090600302016000015485612a95565b90506125bc81612b2d565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612620836111d9565b9050806001600160a01b0316846001600160a01b0316148061266757506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d7a5750836001600160a01b031661268084610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126a5826111d9565b6001600160a01b0316146126cb5760405162461bcd60e51b815260040161092b90613ca2565b6001600160a01b03821661272d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61273a8383836001612f33565b826001600160a01b031661274d826111d9565b6001600160a01b0316146127735760405162461bcd60e51b815260040161092b90613ca2565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280c826124e2565b8154600383015460a01b6001600160a01b0319808416908216036128425760405162461bcd60e51b815260040161092b90613beb565b600184015460001914612899576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128df565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129585760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061297157612971613b43565b9060005260206000209060030201600101548261298e9190613bac565b90504381116129a1575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a48612ffc565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af25760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d7a565b600043600b8381548110612b1257612b12613b43565b90600052602060002090600302016002015411159050919050565b612b3681612afc565b6121995760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061304c565b6001810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1561219c565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a783390565b816001600160a01b0316836001600160a01b031603612db15760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e2a8383612a95565b9050612e3581612b2d565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e79848484612692565b612e8584848484613066565b6117a45760405162461bcd60e51b815260040161092b90613ce7565b60606000612eae83613164565b60010190506000816001600160401b03811115612ecd57612ecd613831565b6040519080825280601f01601f191660200182016040528015612ef7576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f0157509392505050565b80600114612f835760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fab5750600082815260086020526040902060020154600019145b612ff75760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061323c565b60006001600160a01b0384163b1561315c57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130aa903390899088908890600401613d39565b6020604051808303816000875af19250505080156130e5575060408051601f3d908101601f191682019092526130e291810190613d76565b60015b613142573d808015613113576040519150601f19603f3d011682016040523d82523d6000602084013e613118565b606091505b50805160000361313a5760405162461bcd60e51b815260040161092b90613ce7565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d7a565b506001611d7a565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a35772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cf576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131ed57662386f26fc10000830492506010015b6305f5e1008310613205576305f5e100830492506008015b612710831061321957612710830492506004015b6064831061322b576064830492506002015b600a83106109cf5760010192915050565b613246838361326f565b6132536000848484613066565b610bc45760405162461bcd60e51b815260040161092b90613ce7565b6001600160a01b0382166132c55760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561332a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b613338600083836001612f33565b6000818152600260205260409020546001600160a01b03161561339d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219957600080fd5b6000806040838503121561343057600080fd5b82359150602083013561344281613408565b809150509250929050565b6001600160e01b03198116811461219957600080fd5b60006020828403121561347557600080fd5b8135610fbd8161344d565b60006020828403121561349257600080fd5b5035919050565b60005b838110156134b457818101518382015260200161349c565b50506000910152565b600081518084526134d5816020860160208601613499565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134bd565b6000806040838503121561350f57600080fd5b823561351a81613408565b946020939093013593505050565b6000806040838503121561353b57600080fd5b50508035926020909101359150565b60008060006060848603121561355f57600080fd5b833561356a81613408565b9250602084013561357a81613408565b929592945050506040919091013590565b80356001600160a01b0319811681146135a357600080fd5b919050565b600080604083850312156135bb57600080fd5b823591506135cb6020840161358b565b90509250929050565b60008083601f8401126135e657600080fd5b5081356001600160401b038111156135fd57600080fd5b6020830191508360208260051b850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b82356001600160401b0381111561364857600080fd5b613654858286016135d4565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136dc57888603603f19018552825180518088529088019088880190845b818110156136c65783518352928a0192918a01916001016136aa565b5090975050509386019391860191600101613688565b509398975050505050505050565b6000806000604084860312156136ff57600080fd5b83356001600160401b0381111561371557600080fd5b613721868287016135d4565b909790965060209590950135949350505050565b60006020828403121561374757600080fd5b8135610fbd81613408565b602080825282518282018190526000919060409081850190868401855b8281101561379e578151805185528681015187860152850151858501526060909301929085019060010161376f565b5091979650505050505050565b600080604083850312156137be57600080fd5b82356137c981613408565b91506020830135801515811461344257600080fd5b6000806000604084860312156137f357600080fd5b83356001600160401b0381111561380957600080fd5b613815868287016135d4565b909450925061382890506020850161358b565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386f5761386f613831565b604052919050565b6000806000806080858703121561388d57600080fd5b843561389881613408565b93506020858101356138a981613408565b93506040860135925060608601356001600160401b03808211156138cc57600080fd5b818801915088601f8301126138e057600080fd5b8135818111156138f2576138f2613831565b613904601f8201601f19168501613847565b9150808252898482850101111561391a57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394f57600080fd5b83356001600160401b0381111561396557600080fd5b613971868287016135d4565b909450925050602084013561398581613408565b809150509250925092565b600080600080608085870312156139a657600080fd5b84359350602085013592506139bd6040860161358b565b9396929550929360600135925050565b6000806000606084860312156139e257600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0857600080fd5b818701915087601f830112613a1c57600080fd5b813581811115613a2e57613a2e613831565b8060051b9150613a3f848301613847565b818152918301840191848101908a841115613a5957600080fd5b938501935b83851015613a7e57613a6f8561358b565b82529385019390850190613a5e565b8096505050505050509250925092565b60008060408385031215613aa157600080fd5b8235613aac81613408565b9150602083013561344281613408565b600181811c90821680613ad057607f821691505b602082108103613af057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6b57600080fd5b610fbd8261358b565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613b96565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3657600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6e818460208801613499565b835190830190613c82818360208801613499565b01949350505050565b80820281158282048414176109cf576109cf613b96565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6c908301846134bd565b9695505050505050565b600060208284031215613d8857600080fd5b8151610fbd8161344d56fea2646970667358221220838d751ed1580567aada864b691317738d1db46809b8ca2091226ee62191d65464736f6c63430008130033", "rawPrivateKey": "f964b7ccc40ccace513d3159fa9c30514c4a186ebfdd7c63d69cd79a29b804b0", "rawAmount": "0", "rawGasLimit": 20000000, "rawGasPrice": "0", - "rawExpectedGasConsumed": 4885329, + "rawExpectedGasConsumed": 4888337, "expectedStatus": 1, "expectedBalances": [], "comment": "deploy iip13 system staking contract" @@ -43,9 +43,9 @@ "rawGasLimit": 1000000, "rawGasPrice": "0", "rawAccessList": [], - "rawExpectedGasConsumed": 122220, + "rawExpectedGasConsumed": 175893, "expectedStatus": 1, - "expectedLogs": [{}], + "expectedLogs": [{},{}], "rawReturnValue": "", "comment": "stake" } diff --git a/action/protocol/execution/testdata/system-staking.sol b/action/protocol/execution/testdata/system-staking.sol index e5f4451e74..842b29a38d 100644 --- a/action/protocol/execution/testdata/system-staking.sol +++ b/action/protocol/execution/testdata/system-staking.sol @@ -28,7 +28,7 @@ contract SystemStaking is ERC721, Ownable, Pausable { event Locked(uint256 indexed tokenId, uint256 duration); event Unlocked(uint256 indexed tokenId); event Unstaked(uint256 indexed tokenId); - event Merged(uint256[] indexed tokenIds, uint256 amount, uint256 duration); + event Merged(uint256[] tokenIds, uint256 amount, uint256 duration); event DurationExtended(uint256 indexed tokenId, uint256 duration); event AmountIncreased(uint256 indexed tokenId, uint256 amount); event DelegateChanged(uint256 indexed tokenId, bytes12 newDelegate); diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index f483cd35c0..46f123326c 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -36,7 +36,8 @@ import ( ) const ( - _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc980620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089c57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341d565b6108bc565b005b3480156102c557600080fd5b506102d96102d4366004613463565b610983565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613480565b6109d5565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fb565b6040516102e591906134e9565b34801561034a57600080fd5b5061035e610359366004613480565b610a8d565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fc565b610ab4565b3480156103a257600080fd5b506102b76103b1366004613528565b610bc9565b3480156103c257600080fd5b506102b76103d136600461354a565b610c3c565b3480156103e257600080fd5b506102b76103f13660046135a8565b610c6d565b34801561040257600080fd5b506102b7610411366004613480565b610cdb565b34801561042257600080fd5b506102b7610d8a565b34801561043757600080fd5b5061044b61044636600461361f565b610d9c565b6040516102e59190613660565b34801561046457600080fd5b506102b761047336600461354a565b610f18565b34801561048457600080fd5b50610498610493366004613480565b610f33565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613528565b610fa9565b61030e6104f83660046135a8565b610fc4565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136ea565b61103a565b34801561054857600080fd5b506102b761055736600461361f565b6110e1565b34801561056857600080fd5b506102b7610577366004613480565b611177565b34801561058857600080fd5b5061035e610597366004613480565b6111d9565b3480156105a857600080fd5b5061044b6105b736600461361f565b611239565b3480156105c857600080fd5b5061030e6105d7366004613735565b6113ad565b3480156105e857600080fd5b506102b7611433565b3480156105fd57600080fd5b5061061161060c366004613528565b611445565b6040516102e59190613752565b34801561062a57600080fd5b506102b761157a565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c366004613480565b61158a565b34801561067d57600080fd5b506103316115b5565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137ab565b6115c4565b3480156106c757600080fd5b506102b76106d63660046137de565b6115d3565b6102b76106e9366004613528565b61166a565b3480156106fa57600080fd5b506102b7610709366004613877565b611772565b34801561071a57600080fd5b506102b761072936600461393a565b6117aa565b6102b761073c3660046136ea565b611899565b34801561074d57600080fd5b5061033161075c366004613480565b611aa0565b34801561076d57600080fd5b506102b761077c366004613528565b611b13565b61030e61078f366004613990565b611cb8565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613528565b611d82565b61030e6107d83660046139cd565b611e6b565b3480156107e957600080fd5b506102b76107f8366004613528565b611f5d565b34801561080957600080fd5b506102b761081836600461361f565b611fd1565b34801561082957600080fd5b506102d9610838366004613a8e565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613528565b6120ad565b34801561089257600080fd5b5061030e61ca8081565b3480156108a857600080fd5b506102b76108b7366004613735565b612123565b6108c461219c565b816108ce816121e9565b600083815260086020526040902060028101546108ea9061223e565b156109345760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093d846122b3565b6109478184612356565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b457506001600160e01b03198216635b5e139f60e01b145b806109cf57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109e082612415565b6000828152600860205260409020600201546109cf9061223e565b606060008054610a0a90613abc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3690613abc565b8015610a835780601f10610a5857610100808354040283529160200191610a83565b820191906000526020600020905b815481529060010190602001808311610a6657829003601f168201915b5050505050905090565b6000610a9882612415565b506000908152600460205260409020546001600160a01b031690565b6000610abf826111d9565b9050806001600160a01b0316836001600160a01b031603610b2c5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092b565b336001600160a01b0382161480610b485750610b488133610838565b610bba5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092b565b610bc48383612474565b505050565b610bd161219c565b81610bdb816121e9565b6000838152600860205260409020610bf2816124e2565b610bfc818461252c565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2e91815260200190565b60405180910390a250505050565b610c463382612614565b610c625760405162461bcd60e51b815260040161092b90613af6565b610bc4838383612692565b610c7561219c565b81610c7f816121e9565b6000838152600860205260409020610c979083612803565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce361219c565b80610ced816121e9565b6000828152600860205260409020610d04816124e2565b610d0d81612906565b15610d515760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b610d5a816129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d926129e6565b610d9a612a40565b565b6060816001600160401b03811115610db657610db6613831565b604051908082528060200260200182016040528015610de957816020015b6060815260200190600190039081610dd45790505b5090506000610df7600b5490565b905060005b83811015610f1057816001600160401b03811115610e1c57610e1c613831565b604051908082528060200260200182016040528015610e45578160200160208202803683370190505b50838281518110610e5857610e58613b43565b6020026020010181905250600060096000878785818110610e7b57610e7b613b43565b9050602002016020810190610e909190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f06576000818152602083905260409020548551869085908110610eda57610eda613b43565b60200260200101518281518110610ef357610ef3613b43565b6020908102919091010152600101610eaf565b5050600101610dfc565b505092915050565b610bc483838360405180602001604052806000815250611772565b6000806000806000610f4486612415565b60008681526008602052604081208054600b80549293929091908110610f6c57610f6c613b43565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbd610fb88484612a95565b612afc565b9392505050565b6000610fce61219c565b346000610fdb8286612a95565b9050610fe681612b2d565b610ff08185612b79565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102990889087908b90613b74565b60405180910390a295945050505050565b61104261219c565b60008060005b848110156110d95785858281811061106257611062613b43565b905060200201359250611074836121e9565b6000838152600860205260409020915061108d826124e2565b611097828561252c565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c991815260200190565b60405180910390a2600101611048565b505050505050565b6110e961219c565b60008060005b838110156111705784848281811061110957611109613b43565b90506020020135925061111b836121e9565b6000838152600860205260409020915061113482612c19565b61113d82612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ef565b5050505050565b61117f61219c565b80611189816121e9565b60008281526008602052604090206111a081612c19565b6111a981612c63565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cf5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b6060816001600160401b0381111561125357611253613831565b60405190808252806020026020018201604052801561128657816020015b60608152602001906001900390816112715790505b5090506000611294600b5490565b905060005b83811015610f1057816001600160401b038111156112b9576112b9613831565b6040519080825280602002602001820160405280156112e2578160200160208202803683370190505b508382815181106112f5576112f5613b43565b60200260200101819052506000600a600087878581811061131857611318613b43565b905060200201602081019061132d9190613b59565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a357600081815260208390526040902054855186908590811061137757611377613b43565b6020026020010151828151811061139057611390613b43565b602090810291909101015260010161134c565b5050600101611299565b60006001600160a01b0382166114175760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092b565b506001600160a01b031660009081526003602052604090205490565b61143b6129e6565b610d9a6000612cbb565b60606000821180156114625750600b5461145f8385613bac565b11155b61147e5760405162461bcd60e51b815260040161092b90613bbf565b816001600160401b0381111561149657611496613831565b6040519080825280602002602001820160405280156114eb57816020015b6114d860405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b45790505b50905060005b8281101561157357600b8185018154811061150e5761150e613b43565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155757611557613b43565b602002602001018190525061156c8160010190565b90506114f1565b5092915050565b6115826129e6565b610d9a612d0d565b600061159582612415565b60008281526008602052604090206115ac816124e2565b610fbd81612906565b606060018054610a0a90613abc565b6115cf338383612d50565b5050565b6115db61219c565b6000805b83811015611170578484828181106115f9576115f9613b43565b90506020020135915061160b826121e9565b60008281526008602052604090206116239084612803565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115df565b61167261219c565b8161167c816121e9565b600083815260086020526040902061169381612c19565b8054600b805460009190839081106116ad576116ad613b43565b90600052602060002090600302019050848160000154346116ce9190613bac565b146116eb5760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a602090815260408083208584529091529020805460001901905560018101546117309084908790612e1e565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176291815260200190565b60405180910390a2505050505050565b61177c3383612614565b6117985760405162461bcd60e51b815260040161092b90613af6565b6117a484848484612e6e565b50505050565b6117b261219c565b60008060005b848110156110d9578585828181106117d2576117d2613b43565b9050602002013592506117e4836121e9565b600083815260086020526040902060028101549092506118039061223e565b156118485760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092b565b611851836122b3565b61185b8285612356565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b8565b6118a161219c565b600182116118e25760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092b565b3460008080855b8015611a96576000190187878281811061190557611905613b43565b905060200201359350611917846121e9565b60008481526008602052604090209250611930836124e2565b82546003840154600b805460a09290921b918390811061195257611952613b43565b9060005260206000209060030201935083600101548810156119a95760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b83546119b59088613bac565b96506119c78560010154600019141590565b156119fd576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a2a565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3e57611a39866122b3565b611a8f565b6000196001860155611a5185888a612e1e565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a869493929190613c16565b60405180910390a15b50506118e9565b5050505050505050565b6060611aab82612415565b6000611ac260408051602081019091526000815290565b90506000815111611ae25760405180602001604052806000815250610fbd565b80611aec84612ea1565b604051602001611afd929190613c5c565b6040516020818303038152906040529392505050565b611b1b6129e6565b81600003611b5f5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092b565b6000828152600c6020908152604080832084845290915290205415611bbe5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092b565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc261219c565b600082118015611cda575034611cd88387613c8b565b145b611cf65760405162461bcd60e51b815260040161092b90613bbf565b6000611d028686612a95565b9050611d0d81612b2d565b600754600101915060005b83811015611d7757611d2a8286612b79565b611d348184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6793929190613b74565b60405180910390a2600101611d18565b50505b949350505050565b611d8a61219c565b81611d94816121e9565b6000838152600860205260409020611dab81612c19565b8054600b80546000919083908110611dc557611dc5613b43565b9060005260206000209060030201905080600101548511611df85760405162461bcd60e51b815260040161092b90613beb565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3990849087612e1e565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176291815260200190565b6000611e7561219c565b34825185611e839190613c8b565b14611ea05760405162461bcd60e51b815260040161092b90613bbf565b6000611eac8585612a95565b9050611eb781612b2d565b600754600101915060005b8351811015611f5457611eee82858381518110611ee157611ee1613b43565b6020026020010151612b79565b611ef88184613bac565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2b57611f2b613b43565b60200260200101518888604051611f4493929190613b74565b60405180910390a2600101611ec2565b50509392505050565b611f656129e6565b43600b611f728484612a95565b81548110611f8257611f82613b43565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cac929190918252602082015260400190565b611fd961219c565b60008060005b8381101561117057848482818110611ff957611ff9613b43565b90506020020135925061200b836121e9565b60008381526008602052604090209150612024826124e2565b61202d82612906565b156120715760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092b565b61207a826129ab565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fdf565b6120b56129e6565b600019600b6120c48484612a95565b815481106120d4576120d4613b43565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cac929190918252602082015260400190565b61212b6129e6565b6001600160a01b0381166121905760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092b565b61219981612cbb565b50565b600654600160a01b900460ff1615610d9a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092b565b6121f2816111d9565b6001600160a01b0316336001600160a01b0316146121995760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092b565b6000600019820361228a5760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092b565b600061229861ca8084613bac565b90504381116122aa5750600092915050565b43900392915050565b60006122be826111d9565b90506122ce816000846001612f33565b6122d7826111d9565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236f5761236f613b43565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123ca576040519150601f19603f3d011682016040523d82523d6000602084013e6123cf565b606091505b50509050806117a45760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092b565b6000818152600260205260409020546001600160a01b03166121995760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092b565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a9826111d9565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092b565b8154600383015460a01b61253f84612906565b8310156125815760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092b565b60006125b1600b848154811061259957612599613b43565b90600052602060002090600302016000015485612a95565b90506125bc81612b2d565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b600080612620836111d9565b9050806001600160a01b0316846001600160a01b0316148061266757506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d7a5750836001600160a01b031661268084610a8d565b6001600160a01b031614949350505050565b826001600160a01b03166126a5826111d9565b6001600160a01b0316146126cb5760405162461bcd60e51b815260040161092b90613ca2565b6001600160a01b03821661272d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092b565b61273a8383836001612f33565b826001600160a01b031661274d826111d9565b6001600160a01b0316146127735760405162461bcd60e51b815260040161092b90613ca2565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280c826124e2565b8154600383015460a01b6001600160a01b0319808416908216036128425760405162461bcd60e51b815260040161092b90613beb565b600184015460001914612899576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128df565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129585760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092b565b6000600b84600001548154811061297157612971613b43565b9060005260206000209060030201600101548261298e9190613bac565b90504381116129a1575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d9a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092b565b612a48612ffc565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af25760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092b565b6000198101611d7a565b600043600b8381548110612b1257612b12613b43565b90600052602060002090600302016002015411159050919050565b612b3681612afc565b6121995760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092b565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115cf90339061304c565b6001810154600019146121995760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092b565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1561219c565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a783390565b816001600160a01b0316836001600160a01b031603612db15760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092b565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e2a8383612a95565b9050612e3581612b2d565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e79848484612692565b612e8584848484613066565b6117a45760405162461bcd60e51b815260040161092b90613ce7565b60606000612eae83613164565b60010190506000816001600160401b03811115612ecd57612ecd613831565b6040519080825280601f01601f191660200182016040528015612ef7576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f0157509392505050565b80600114612f835760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092b565b6001600160a01b0383161580612fab5750600082815260086020526040902060020154600019145b612ff75760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092b565b6117a4565b600654600160a01b900460ff16610d9a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092b565b6115cf82826040518060200160405280600081525061323c565b60006001600160a01b0384163b1561315c57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130aa903390899088908890600401613d39565b6020604051808303816000875af19250505080156130e5575060408051601f3d908101601f191682019092526130e291810190613d76565b60015b613142573d808015613113576040519150601f19603f3d011682016040523d82523d6000602084013e613118565b606091505b50805160000361313a5760405162461bcd60e51b815260040161092b90613ce7565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d7a565b506001611d7a565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a35772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cf576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131ed57662386f26fc10000830492506010015b6305f5e1008310613205576305f5e100830492506008015b612710831061321957612710830492506004015b6064831061322b576064830492506002015b600a83106109cf5760010192915050565b613246838361326f565b6132536000848484613066565b610bc45760405162461bcd60e51b815260040161092b90613ce7565b6001600160a01b0382166132c55760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092b565b6000818152600260205260409020546001600160a01b03161561332a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b613338600083836001612f33565b6000818152600260205260409020546001600160a01b03161561339d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092b565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219957600080fd5b6000806040838503121561343057600080fd5b82359150602083013561344281613408565b809150509250929050565b6001600160e01b03198116811461219957600080fd5b60006020828403121561347557600080fd5b8135610fbd8161344d565b60006020828403121561349257600080fd5b5035919050565b60005b838110156134b457818101518382015260200161349c565b50506000910152565b600081518084526134d5816020860160208601613499565b601f01601f19169290920160200192915050565b602081526000610fbd60208301846134bd565b6000806040838503121561350f57600080fd5b823561351a81613408565b946020939093013593505050565b6000806040838503121561353b57600080fd5b50508035926020909101359150565b60008060006060848603121561355f57600080fd5b833561356a81613408565b9250602084013561357a81613408565b929592945050506040919091013590565b80356001600160a01b0319811681146135a357600080fd5b919050565b600080604083850312156135bb57600080fd5b823591506135cb6020840161358b565b90509250929050565b60008083601f8401126135e657600080fd5b5081356001600160401b038111156135fd57600080fd5b6020830191508360208260051b850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b82356001600160401b0381111561364857600080fd5b613654858286016135d4565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136dc57888603603f19018552825180518088529088019088880190845b818110156136c65783518352928a0192918a01916001016136aa565b5090975050509386019391860191600101613688565b509398975050505050505050565b6000806000604084860312156136ff57600080fd5b83356001600160401b0381111561371557600080fd5b613721868287016135d4565b909790965060209590950135949350505050565b60006020828403121561374757600080fd5b8135610fbd81613408565b602080825282518282018190526000919060409081850190868401855b8281101561379e578151805185528681015187860152850151858501526060909301929085019060010161376f565b5091979650505050505050565b600080604083850312156137be57600080fd5b82356137c981613408565b91506020830135801515811461344257600080fd5b6000806000604084860312156137f357600080fd5b83356001600160401b0381111561380957600080fd5b613815868287016135d4565b909450925061382890506020850161358b565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386f5761386f613831565b604052919050565b6000806000806080858703121561388d57600080fd5b843561389881613408565b93506020858101356138a981613408565b93506040860135925060608601356001600160401b03808211156138cc57600080fd5b818801915088601f8301126138e057600080fd5b8135818111156138f2576138f2613831565b613904601f8201601f19168501613847565b9150808252898482850101111561391a57600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394f57600080fd5b83356001600160401b0381111561396557600080fd5b613971868287016135d4565b909450925050602084013561398581613408565b809150509250925092565b600080600080608085870312156139a657600080fd5b84359350602085013592506139bd6040860161358b565b9396929550929360600135925050565b6000806000606084860312156139e257600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0857600080fd5b818701915087601f830112613a1c57600080fd5b813581811115613a2e57613a2e613831565b8060051b9150613a3f848301613847565b818152918301840191848101908a841115613a5957600080fd5b938501935b83851015613a7e57613a6f8561358b565b82529385019390850190613a5e565b8096505050505050509250925092565b60008060408385031215613aa157600080fd5b8235613aac81613408565b9150602083013561344281613408565b600181811c90821680613ad057607f821691505b602082108103613af057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6b57600080fd5b610fbd8261358b565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109cf576109cf613b96565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3657600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6e818460208801613499565b835190830190613c82818360208801613499565b01949350505050565b80820281158282048414176109cf576109cf613b96565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6c908301846134bd565b9695505050505050565b600060208284031215613d8857600080fd5b8151610fbd8161344d56fea2646970667358221220838d751ed1580567aada864b691317738d1db46809b8ca2091226ee62191d65464736f6c63430008130033` + // _liquidStakingContractByteCode is the byte code of the liquid staking contract for testing, which changes the freeze blocks to 10 + _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc780620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089b57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341b565b6108bb565b005b3480156102c557600080fd5b506102d96102d4366004613461565b610982565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e61030936600461347e565b6109d4565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fa565b6040516102e591906134e7565b34801561034a57600080fd5b5061035e61035936600461347e565b610a8c565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fa565b610ab3565b3480156103a257600080fd5b506102b76103b1366004613526565b610bc8565b3480156103c257600080fd5b506102b76103d1366004613548565b610c3b565b3480156103e257600080fd5b506102b76103f13660046135a6565b610c6c565b34801561040257600080fd5b506102b761041136600461347e565b610cda565b34801561042257600080fd5b506102b7610d89565b34801561043757600080fd5b5061044b61044636600461361d565b610d9b565b6040516102e5919061365e565b34801561046457600080fd5b506102b7610473366004613548565b610f17565b34801561048457600080fd5b5061049861049336600461347e565b610f32565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613526565b610fa8565b61030e6104f83660046135a6565b610fc3565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136e8565b611039565b34801561054857600080fd5b506102b761055736600461361d565b6110e0565b34801561056857600080fd5b506102b761057736600461347e565b611176565b34801561058857600080fd5b5061035e61059736600461347e565b6111d8565b3480156105a857600080fd5b5061044b6105b736600461361d565b611238565b3480156105c857600080fd5b5061030e6105d7366004613733565b6113ac565b3480156105e857600080fd5b506102b7611432565b3480156105fd57600080fd5b5061061161060c366004613526565b611444565b6040516102e59190613750565b34801561062a57600080fd5b506102b7611579565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c36600461347e565b611589565b34801561067d57600080fd5b506103316115b4565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137a9565b6115c3565b3480156106c757600080fd5b506102b76106d63660046137dc565b6115d2565b6102b76106e9366004613526565b611669565b3480156106fa57600080fd5b506102b7610709366004613875565b611771565b34801561071a57600080fd5b506102b7610729366004613938565b6117a9565b6102b761073c3660046136e8565b611898565b34801561074d57600080fd5b5061033161075c36600461347e565b611a9f565b34801561076d57600080fd5b506102b761077c366004613526565b611b12565b61030e61078f36600461398e565b611cb7565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613526565b611d81565b61030e6107d83660046139cb565b611e6a565b3480156107e957600080fd5b506102b76107f8366004613526565b611f5c565b34801561080957600080fd5b506102b761081836600461361d565b611fd0565b34801561082957600080fd5b506102d9610838366004613a8c565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613526565b6120ac565b34801561089257600080fd5b5061030e600a81565b3480156108a757600080fd5b506102b76108b6366004613733565b612122565b6108c361219b565b816108cd816121e8565b600083815260086020526040902060028101546108e99061223d565b156109335760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093c846122b1565b6109468184612354565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b357506001600160e01b03198216635b5e139f60e01b145b806109ce57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109df82612413565b6000828152600860205260409020600201546109ce9061223d565b606060008054610a0990613aba565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3590613aba565b8015610a825780601f10610a5757610100808354040283529160200191610a82565b820191906000526020600020905b815481529060010190602001808311610a6557829003601f168201915b5050505050905090565b6000610a9782612413565b506000908152600460205260409020546001600160a01b031690565b6000610abe826111d8565b9050806001600160a01b0316836001600160a01b031603610b2b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092a565b336001600160a01b0382161480610b475750610b478133610838565b610bb95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092a565b610bc38383612472565b505050565b610bd061219b565b81610bda816121e8565b6000838152600860205260409020610bf1816124e0565b610bfb818461252a565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2d91815260200190565b60405180910390a250505050565b610c453382612612565b610c615760405162461bcd60e51b815260040161092a90613af4565b610bc3838383612690565b610c7461219b565b81610c7e816121e8565b6000838152600860205260409020610c969083612801565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce261219b565b80610cec816121e8565b6000828152600860205260409020610d03816124e0565b610d0c81612904565b15610d505760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b610d59816129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d916129e4565b610d99612a3e565b565b6060816001600160401b03811115610db557610db561382f565b604051908082528060200260200182016040528015610de857816020015b6060815260200190600190039081610dd35790505b5090506000610df6600b5490565b905060005b83811015610f0f57816001600160401b03811115610e1b57610e1b61382f565b604051908082528060200260200182016040528015610e44578160200160208202803683370190505b50838281518110610e5757610e57613b41565b6020026020010181905250600060096000878785818110610e7a57610e7a613b41565b9050602002016020810190610e8f9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f05576000818152602083905260409020548551869085908110610ed957610ed9613b41565b60200260200101518281518110610ef257610ef2613b41565b6020908102919091010152600101610eae565b5050600101610dfb565b505092915050565b610bc383838360405180602001604052806000815250611771565b6000806000806000610f4386612413565b60008681526008602052604081208054600b80549293929091908110610f6b57610f6b613b41565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbc610fb78484612a93565b612afa565b9392505050565b6000610fcd61219b565b346000610fda8286612a93565b9050610fe581612b2b565b610fef8185612b77565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102890889087908b90613b72565b60405180910390a295945050505050565b61104161219b565b60008060005b848110156110d85785858281811061106157611061613b41565b905060200201359250611073836121e8565b6000838152600860205260409020915061108c826124e0565b611096828561252a565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c891815260200190565b60405180910390a2600101611047565b505050505050565b6110e861219b565b60008060005b8381101561116f5784848281811061110857611108613b41565b90506020020135925061111a836121e8565b6000838152600860205260409020915061113382612c17565b61113c82612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ee565b5050505050565b61117e61219b565b80611188816121e8565b600082815260086020526040902061119f81612c17565b6111a881612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109ce5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b6060816001600160401b038111156112525761125261382f565b60405190808252806020026020018201604052801561128557816020015b60608152602001906001900390816112705790505b5090506000611293600b5490565b905060005b83811015610f0f57816001600160401b038111156112b8576112b861382f565b6040519080825280602002602001820160405280156112e1578160200160208202803683370190505b508382815181106112f4576112f4613b41565b60200260200101819052506000600a600087878581811061131757611317613b41565b905060200201602081019061132c9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a257600081815260208390526040902054855186908590811061137657611376613b41565b6020026020010151828151811061138f5761138f613b41565b602090810291909101015260010161134b565b5050600101611298565b60006001600160a01b0382166114165760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092a565b506001600160a01b031660009081526003602052604090205490565b61143a6129e4565b610d996000612cb9565b60606000821180156114615750600b5461145e8385613baa565b11155b61147d5760405162461bcd60e51b815260040161092a90613bbd565b816001600160401b038111156114955761149561382f565b6040519080825280602002602001820160405280156114ea57816020015b6114d760405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b35790505b50905060005b8281101561157257600b8185018154811061150d5761150d613b41565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155657611556613b41565b602002602001018190525061156b8160010190565b90506114f0565b5092915050565b6115816129e4565b610d99612d0b565b600061159482612413565b60008281526008602052604090206115ab816124e0565b610fbc81612904565b606060018054610a0990613aba565b6115ce338383612d4e565b5050565b6115da61219b565b6000805b8381101561116f578484828181106115f8576115f8613b41565b90506020020135915061160a826121e8565b60008281526008602052604090206116229084612801565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115de565b61167161219b565b8161167b816121e8565b600083815260086020526040902061169281612c17565b8054600b805460009190839081106116ac576116ac613b41565b90600052602060002090600302019050848160000154346116cd9190613baa565b146116ea5760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a6020908152604080832085845290915290208054600019019055600181015461172f9084908790612e1c565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176191815260200190565b60405180910390a2505050505050565b61177b3383612612565b6117975760405162461bcd60e51b815260040161092a90613af4565b6117a384848484612e6c565b50505050565b6117b161219b565b60008060005b848110156110d8578585828181106117d1576117d1613b41565b9050602002013592506117e3836121e8565b600083815260086020526040902060028101549092506118029061223d565b156118475760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092a565b611850836122b1565b61185a8285612354565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b7565b6118a061219b565b600182116118e15760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092a565b3460008080855b8015611a95576000190187878281811061190457611904613b41565b905060200201359350611916846121e8565b6000848152600860205260409020925061192f836124e0565b82546003840154600b805460a09290921b918390811061195157611951613b41565b9060005260206000209060030201935083600101548810156119a85760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b83546119b49088613baa565b96506119c68560010154600019141590565b156119fc576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a29565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3d57611a38866122b1565b611a8e565b6000196001860155611a5085888a612e1c565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a859493929190613c14565b60405180910390a15b50506118e8565b5050505050505050565b6060611aaa82612413565b6000611ac160408051602081019091526000815290565b90506000815111611ae15760405180602001604052806000815250610fbc565b80611aeb84612e9f565b604051602001611afc929190613c5a565b6040516020818303038152906040529392505050565b611b1a6129e4565b81600003611b5e5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092a565b6000828152600c6020908152604080832084845290915290205415611bbd5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092a565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc161219b565b600082118015611cd9575034611cd78387613c89565b145b611cf55760405162461bcd60e51b815260040161092a90613bbd565b6000611d018686612a93565b9050611d0c81612b2b565b600754600101915060005b83811015611d7657611d298286612b77565b611d338184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6693929190613b72565b60405180910390a2600101611d17565b50505b949350505050565b611d8961219b565b81611d93816121e8565b6000838152600860205260409020611daa81612c17565b8054600b80546000919083908110611dc457611dc4613b41565b9060005260206000209060030201905080600101548511611df75760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3890849087612e1c565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176191815260200190565b6000611e7461219b565b34825185611e829190613c89565b14611e9f5760405162461bcd60e51b815260040161092a90613bbd565b6000611eab8585612a93565b9050611eb681612b2b565b600754600101915060005b8351811015611f5357611eed82858381518110611ee057611ee0613b41565b6020026020010151612b77565b611ef78184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2a57611f2a613b41565b60200260200101518888604051611f4393929190613b72565b60405180910390a2600101611ec1565b50509392505050565b611f646129e4565b43600b611f718484612a93565b81548110611f8157611f81613b41565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cab929190918252602082015260400190565b611fd861219b565b60008060005b8381101561116f57848482818110611ff857611ff8613b41565b90506020020135925061200a836121e8565b60008381526008602052604090209150612023826124e0565b61202c82612904565b156120705760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b612079826129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fde565b6120b46129e4565b600019600b6120c38484612a93565b815481106120d3576120d3613b41565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cab929190918252602082015260400190565b61212a6129e4565b6001600160a01b03811661218f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092a565b61219881612cb9565b50565b600654600160a01b900460ff1615610d995760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092a565b6121f1816111d8565b6001600160a01b0316336001600160a01b0316146121985760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092a565b600060001982036122895760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092a565b6000612296600a84613baa565b90504381116122a85750600092915050565b43900392915050565b60006122bc826111d8565b90506122cc816000846001612f31565b6122d5826111d8565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236d5761236d613b41565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123c8576040519150601f19603f3d011682016040523d82523d6000602084013e6123cd565b606091505b50509050806117a35760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092a565b6000818152600260205260409020546001600160a01b03166121985760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a7826111d8565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092a565b8154600383015460a01b61253d84612904565b83101561257f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b60006125af600b848154811061259757612597613b41565b90600052602060002090600302016000015485612a93565b90506125ba81612b2b565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061261e836111d8565b9050806001600160a01b0316846001600160a01b0316148061266557506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d795750836001600160a01b031661267e84610a8c565b6001600160a01b031614949350505050565b826001600160a01b03166126a3826111d8565b6001600160a01b0316146126c95760405162461bcd60e51b815260040161092a90613ca0565b6001600160a01b03821661272b5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092a565b6127388383836001612f31565b826001600160a01b031661274b826111d8565b6001600160a01b0316146127715760405162461bcd60e51b815260040161092a90613ca0565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280a826124e0565b8154600383015460a01b6001600160a01b0319808416908216036128405760405162461bcd60e51b815260040161092a90613be9565b600184015460001914612897576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128dd565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129565760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092a565b6000600b84600001548154811061296f5761296f613b41565b9060005260206000209060030201600101548261298c9190613baa565b905043811161299f575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d995760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092a565b612a46612ffa565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af05760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092a565b6000198101611d79565b600043600b8381548110612b1057612b10613b41565b90600052602060002090600302016002015411159050919050565b612b3481612afa565b6121985760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092a565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115ce90339061304a565b6001810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092a565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1361219b565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a763390565b816001600160a01b0316836001600160a01b031603612daf5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e288383612a93565b9050612e3381612b2b565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e77848484612690565b612e8384848484613064565b6117a35760405162461bcd60e51b815260040161092a90613ce5565b60606000612eac83613162565b60010190506000816001600160401b03811115612ecb57612ecb61382f565b6040519080825280601f01601f191660200182016040528015612ef5576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612eff57509392505050565b80600114612f815760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092a565b6001600160a01b0383161580612fa95750600082815260086020526040902060020154600019145b612ff55760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092a565b6117a3565b600654600160a01b900460ff16610d995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092a565b6115ce82826040518060200160405280600081525061323a565b60006001600160a01b0384163b1561315a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130a8903390899088908890600401613d37565b6020604051808303816000875af19250505080156130e3575060408051601f3d908101601f191682019092526130e091810190613d74565b60015b613140573d808015613111576040519150601f19603f3d011682016040523d82523d6000602084013e613116565b606091505b5080516000036131385760405162461bcd60e51b815260040161092a90613ce5565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d79565b506001611d79565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a15772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cd576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131eb57662386f26fc10000830492506010015b6305f5e1008310613203576305f5e100830492506008015b612710831061321757612710830492506004015b60648310613229576064830492506002015b600a83106109ce5760010192915050565b613244838361326d565b6132516000848484613064565b610bc35760405162461bcd60e51b815260040161092a90613ce5565b6001600160a01b0382166132c35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092a565b6000818152600260205260409020546001600160a01b0316156133285760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b613336600083836001612f31565b6000818152600260205260409020546001600160a01b03161561339b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219857600080fd5b6000806040838503121561342e57600080fd5b82359150602083013561344081613406565b809150509250929050565b6001600160e01b03198116811461219857600080fd5b60006020828403121561347357600080fd5b8135610fbc8161344b565b60006020828403121561349057600080fd5b5035919050565b60005b838110156134b257818101518382015260200161349a565b50506000910152565b600081518084526134d3816020860160208601613497565b601f01601f19169290920160200192915050565b602081526000610fbc60208301846134bb565b6000806040838503121561350d57600080fd5b823561351881613406565b946020939093013593505050565b6000806040838503121561353957600080fd5b50508035926020909101359150565b60008060006060848603121561355d57600080fd5b833561356881613406565b9250602084013561357881613406565b929592945050506040919091013590565b80356001600160a01b0319811681146135a157600080fd5b919050565b600080604083850312156135b957600080fd5b823591506135c960208401613589565b90509250929050565b60008083601f8401126135e457600080fd5b5081356001600160401b038111156135fb57600080fd5b6020830191508360208260051b850101111561361657600080fd5b9250929050565b6000806020838503121561363057600080fd5b82356001600160401b0381111561364657600080fd5b613652858286016135d2565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136da57888603603f19018552825180518088529088019088880190845b818110156136c45783518352928a0192918a01916001016136a8565b5090975050509386019391860191600101613686565b509398975050505050505050565b6000806000604084860312156136fd57600080fd5b83356001600160401b0381111561371357600080fd5b61371f868287016135d2565b909790965060209590950135949350505050565b60006020828403121561374557600080fd5b8135610fbc81613406565b602080825282518282018190526000919060409081850190868401855b8281101561379c578151805185528681015187860152850151858501526060909301929085019060010161376d565b5091979650505050505050565b600080604083850312156137bc57600080fd5b82356137c781613406565b91506020830135801515811461344057600080fd5b6000806000604084860312156137f157600080fd5b83356001600160401b0381111561380757600080fd5b613813868287016135d2565b9094509250613826905060208501613589565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386d5761386d61382f565b604052919050565b6000806000806080858703121561388b57600080fd5b843561389681613406565b93506020858101356138a781613406565b93506040860135925060608601356001600160401b03808211156138ca57600080fd5b818801915088601f8301126138de57600080fd5b8135818111156138f0576138f061382f565b613902601f8201601f19168501613845565b9150808252898482850101111561391857600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394d57600080fd5b83356001600160401b0381111561396357600080fd5b61396f868287016135d2565b909450925050602084013561398381613406565b809150509250925092565b600080600080608085870312156139a457600080fd5b84359350602085013592506139bb60408601613589565b9396929550929360600135925050565b6000806000606084860312156139e057600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0657600080fd5b818701915087601f830112613a1a57600080fd5b813581811115613a2c57613a2c61382f565b8060051b9150613a3d848301613845565b818152918301840191848101908a841115613a5757600080fd5b938501935b83851015613a7c57613a6d85613589565b82529385019390850190613a5c565b8096505050505050509250925092565b60008060408385031215613a9f57600080fd5b8235613aaa81613406565b9150602083013561344081613406565b600181811c90821680613ace57607f821691505b602082108103613aee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6957600080fd5b610fbc82613589565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109ce576109ce613b94565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3457600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6c818460208801613497565b835190830190613c80818360208801613497565b01949350505050565b80820281158282048414176109ce576109ce613b94565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6a908301846134bb565b9695505050505050565b600060208284031215613d8657600080fd5b8151610fbc8161344b56fea264697066735822122033a72ba2419a7cb3b00b4b4de4305d6458e98ea74f8be8cc9c16afc85a97571764736f6c63430008130033` ) func TestLiquidStaking(t *testing.T) { @@ -178,7 +179,8 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(0, indexer.GetCandidateVotes("delegate2").Int64()) t.Run("withdraw", func(t *testing.T) { - // jumpBlocks(bc, 3*24*3600/5, r) + // freeze blocks are changed to 10 in test + jumpBlocks(bc, 10, r) tokenID := bt.Index addr := common.BytesToAddress(identityset.PrivateKey(1).PublicKey().Bytes()) @@ -194,10 +196,10 @@ func TestLiquidStaking(t *testing.T) { } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) - // r.EqualValues("", receipts[0].ExecutionRevertMsg()) - // r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - // bt, err = indexer.GetBucket(uint64(tokenID)) - // r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) + r.EqualValues("", receipts[0].ExecutionRevertMsg()) + r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) + bt, err = indexer.GetBucket(uint64(tokenID)) + r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) }) }) }) From 7fb8041bbb548dc3a2a29d8d5a28407d837f5b29 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 28 Apr 2023 11:56:52 +0800 Subject: [PATCH 21/51] fix lint issue --- blockindex/liquidstaking_indexer.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index e3870217d3..e2971f6df3 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -31,6 +31,7 @@ import ( const ( // TODO (iip-13): replace with the real liquid staking contract address + // LiquidStakingContractAddress is the address of liquid staking contract LiquidStakingContractAddress = "io1dkqh5mu9djfas3xyrmzdv9frsmmytel4mp7a64" // LiquidStakingContractABI is the ABI of liquid staking contract LiquidStakingContractABI = `[ @@ -1365,6 +1366,7 @@ func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) Li } } +// Start starts the indexer func (s *liquidStakingIndexer) Start(ctx context.Context) error { if err := s.kvstore.Start(ctx); err != nil { return err @@ -1372,6 +1374,7 @@ func (s *liquidStakingIndexer) Start(ctx context.Context) error { return s.loadCache() } +// Stop stops the indexer func (s *liquidStakingIndexer) Stop(ctx context.Context) error { if err := s.kvstore.Stop(ctx); err != nil { return err @@ -1379,6 +1382,7 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { return nil } +// PutBlock puts a block into indexer func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { actionMap := make(map[hash.Hash256]*action.SealedEnvelope) for _, act := range blk.Actions { @@ -1410,18 +1414,22 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e return s.commit() } +// DeleteTipBlock deletes the tip block from indexer func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { return errors.New("not implemented") } +// Height returns the tip block height func (s *liquidStakingIndexer) Height() (uint64, error) { return s.cleanCache.getHeight(), nil } +// GetCandidateVotes returns the candidate votes func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { return s.cleanCache.getCandidateVotes(candidate) } +// GetBuckets returns the buckets func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { vbs := []*Bucket{} for id, bi := range s.cleanCache.idBucketMap { @@ -1435,6 +1443,7 @@ func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { return vbs, nil } +// GetBucket returns the bucket func (s *liquidStakingIndexer) GetBucket(id uint64) (*Bucket, error) { bi, ok := s.cleanCache.idBucketMap[id] if !ok { From 883ddb9b1e9453f809a5942687fb73b94a98ade7 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 28 Apr 2023 15:12:16 +0800 Subject: [PATCH 22/51] refactor --- blockindex/liquidstaking_indexer.go | 941 +------------------- e2etest/liquid_staking_test.go | 1263 ++++++++++++++++++++++++++- 2 files changed, 1270 insertions(+), 934 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index e2971f6df3..e92cb76d19 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -30,16 +30,11 @@ import ( ) const ( - // TODO (iip-13): replace with the real liquid staking contract address // LiquidStakingContractAddress is the address of liquid staking contract + // TODO (iip-13): replace with the real liquid staking contract address LiquidStakingContractAddress = "io1dkqh5mu9djfas3xyrmzdv9frsmmytel4mp7a64" // LiquidStakingContractABI is the ABI of liquid staking contract LiquidStakingContractABI = `[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "anonymous": false, "inputs": [ @@ -374,895 +369,6 @@ const ( ], "name": "Withdrawal", "type": "event" - }, - { - "inputs": [], - "name": "UINT256_MAX", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "UNSTAKE_FREEZE_BLOCKS", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "activateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "addBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "blocksToUnstake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "blocksToWithdraw", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "bucketOf", - "outputs": [ - { - "internalType": "uint256", - "name": "amount_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "duration_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unlockedAt_", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "unstakedAt_", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "delegate_", - "type": "bytes12" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_offset", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_size", - "type": "uint256" - } - ], - "name": "bucketTypes", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "duration", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "activatedAt", - "type": "uint256" - } - ], - "internalType": "struct BucketType[]", - "name": "types_", - "type": "tuple[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "changeDelegates", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "deactivateBucketType", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newDuration", - "type": "uint256" - } - ], - "name": "extendDuration", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_newAmount", - "type": "uint256" - } - ], - "name": "increaseAmount", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "isActiveBucketType", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "lock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - } - ], - "name": "lock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "lockedVotesTo", - "outputs": [ - { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "_newDuration", - "type": "uint256" - } - ], - "name": "merge", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "numOfBucketTypes", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12", - "name": "_delegate", - "type": "bytes12" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256", - "name": "firstTokenId_", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_duration", - "type": "uint256" - }, - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "stake", - "outputs": [ - { - "internalType": "uint256", - "name": "firstTokenId_", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - } - ], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "unlock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes12[]", - "name": "_delegates", - "type": "bytes12[]" - } - ], - "name": "unlockedVotesTo", - "outputs": [ - { - "internalType": "uint256[][]", - "name": "counts_", - "type": "uint256[][]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - } - ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - } - ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_tokenId", - "type": "uint256" - }, - { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256[]", - "name": "_tokenIds", - "type": "uint256[]" - }, - { - "internalType": "address payable", - "name": "_recipient", - "type": "address" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" } ]` @@ -1277,9 +383,9 @@ type ( LiquidStakingIndexer interface { blockdao.BlockIndexer - GetCandidateVotes(candidate string) *big.Int - GetBuckets() ([]*Bucket, error) - GetBucket(id uint64) (*Bucket, error) + CandidateVotes(candidate string) *big.Int + Buckets() ([]*Bucket, error) + Bucket(id uint64) (*Bucket, error) } liquidStakingIndexer struct { @@ -1424,13 +530,13 @@ func (s *liquidStakingIndexer) Height() (uint64, error) { return s.cleanCache.getHeight(), nil } -// GetCandidateVotes returns the candidate votes -func (s *liquidStakingIndexer) GetCandidateVotes(candidate string) *big.Int { +// CandidateVotes returns the candidate votes +func (s *liquidStakingIndexer) CandidateVotes(candidate string) *big.Int { return s.cleanCache.getCandidateVotes(candidate) } -// GetBuckets returns the buckets -func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { +// Buckets returns the buckets +func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { vbs := []*Bucket{} for id, bi := range s.cleanCache.idBucketMap { bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) @@ -1443,8 +549,8 @@ func (s *liquidStakingIndexer) GetBuckets() ([]*Bucket, error) { return vbs, nil } -// GetBucket returns the bucket -func (s *liquidStakingIndexer) GetBucket(id uint64) (*Bucket, error) { +// Bucket returns the bucket +func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { bi, ok := s.cleanCache.idBucketMap[id] if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) @@ -1474,33 +580,32 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block timestamp := blk.Timestamp() switch abiEvent.Name { case "BucketTypeActivated": - err = s.handleBucketTypeActivatedEvent(event, timestamp) + return s.handleBucketTypeActivatedEvent(event, timestamp) case "BucketTypeDeactivated": - err = s.handleBucketTypeDeactivatedEvent(event) + return s.handleBucketTypeDeactivatedEvent(event) case "Staked": - err = s.handleStakedEvent(event, timestamp) + return s.handleStakedEvent(event, timestamp) case "Locked": - err = s.handleLockedEvent(event) + return s.handleLockedEvent(event) case "Unlocked": - err = s.handleUnlockedEvent(event, timestamp) + return s.handleUnlockedEvent(event, timestamp) case "Unstaked": - err = s.handleUnstakedEvent(event, timestamp) + return s.handleUnstakedEvent(event, timestamp) case "Merged": - err = s.handleMergedEvent(event) + return s.handleMergedEvent(event) case "DurationExtended": - err = s.handleDurationExtendedEvent(event) + return s.handleDurationExtendedEvent(event) case "AmountIncreased": - err = s.handleAmountIncreasedEvent(event) + return s.handleAmountIncreasedEvent(event) case "DelegateChanged": - err = s.handleDelegateChangedEvent(event) + return s.handleDelegateChangedEvent(event) case "Withdrawal": - err = s.handleWithdrawalEvent(event) + return s.handleWithdrawalEvent(event) case "Transfer": - err = s.handleTransferEvent(event) + return s.handleTransferEvent(event) default: - err = nil + return nil } - return err } func (s *liquidStakingIndexer) handleTransferEvent(event eventParam) error { diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 46f123326c..0062851e35 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -38,6 +38,1237 @@ import ( const ( // _liquidStakingContractByteCode is the byte code of the liquid staking contract for testing, which changes the freeze blocks to 10 _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc780620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089b57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341b565b6108bb565b005b3480156102c557600080fd5b506102d96102d4366004613461565b610982565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e61030936600461347e565b6109d4565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fa565b6040516102e591906134e7565b34801561034a57600080fd5b5061035e61035936600461347e565b610a8c565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fa565b610ab3565b3480156103a257600080fd5b506102b76103b1366004613526565b610bc8565b3480156103c257600080fd5b506102b76103d1366004613548565b610c3b565b3480156103e257600080fd5b506102b76103f13660046135a6565b610c6c565b34801561040257600080fd5b506102b761041136600461347e565b610cda565b34801561042257600080fd5b506102b7610d89565b34801561043757600080fd5b5061044b61044636600461361d565b610d9b565b6040516102e5919061365e565b34801561046457600080fd5b506102b7610473366004613548565b610f17565b34801561048457600080fd5b5061049861049336600461347e565b610f32565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613526565b610fa8565b61030e6104f83660046135a6565b610fc3565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136e8565b611039565b34801561054857600080fd5b506102b761055736600461361d565b6110e0565b34801561056857600080fd5b506102b761057736600461347e565b611176565b34801561058857600080fd5b5061035e61059736600461347e565b6111d8565b3480156105a857600080fd5b5061044b6105b736600461361d565b611238565b3480156105c857600080fd5b5061030e6105d7366004613733565b6113ac565b3480156105e857600080fd5b506102b7611432565b3480156105fd57600080fd5b5061061161060c366004613526565b611444565b6040516102e59190613750565b34801561062a57600080fd5b506102b7611579565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c36600461347e565b611589565b34801561067d57600080fd5b506103316115b4565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137a9565b6115c3565b3480156106c757600080fd5b506102b76106d63660046137dc565b6115d2565b6102b76106e9366004613526565b611669565b3480156106fa57600080fd5b506102b7610709366004613875565b611771565b34801561071a57600080fd5b506102b7610729366004613938565b6117a9565b6102b761073c3660046136e8565b611898565b34801561074d57600080fd5b5061033161075c36600461347e565b611a9f565b34801561076d57600080fd5b506102b761077c366004613526565b611b12565b61030e61078f36600461398e565b611cb7565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613526565b611d81565b61030e6107d83660046139cb565b611e6a565b3480156107e957600080fd5b506102b76107f8366004613526565b611f5c565b34801561080957600080fd5b506102b761081836600461361d565b611fd0565b34801561082957600080fd5b506102d9610838366004613a8c565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613526565b6120ac565b34801561089257600080fd5b5061030e600a81565b3480156108a757600080fd5b506102b76108b6366004613733565b612122565b6108c361219b565b816108cd816121e8565b600083815260086020526040902060028101546108e99061223d565b156109335760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093c846122b1565b6109468184612354565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b357506001600160e01b03198216635b5e139f60e01b145b806109ce57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109df82612413565b6000828152600860205260409020600201546109ce9061223d565b606060008054610a0990613aba565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3590613aba565b8015610a825780601f10610a5757610100808354040283529160200191610a82565b820191906000526020600020905b815481529060010190602001808311610a6557829003601f168201915b5050505050905090565b6000610a9782612413565b506000908152600460205260409020546001600160a01b031690565b6000610abe826111d8565b9050806001600160a01b0316836001600160a01b031603610b2b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092a565b336001600160a01b0382161480610b475750610b478133610838565b610bb95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092a565b610bc38383612472565b505050565b610bd061219b565b81610bda816121e8565b6000838152600860205260409020610bf1816124e0565b610bfb818461252a565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2d91815260200190565b60405180910390a250505050565b610c453382612612565b610c615760405162461bcd60e51b815260040161092a90613af4565b610bc3838383612690565b610c7461219b565b81610c7e816121e8565b6000838152600860205260409020610c969083612801565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce261219b565b80610cec816121e8565b6000828152600860205260409020610d03816124e0565b610d0c81612904565b15610d505760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b610d59816129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d916129e4565b610d99612a3e565b565b6060816001600160401b03811115610db557610db561382f565b604051908082528060200260200182016040528015610de857816020015b6060815260200190600190039081610dd35790505b5090506000610df6600b5490565b905060005b83811015610f0f57816001600160401b03811115610e1b57610e1b61382f565b604051908082528060200260200182016040528015610e44578160200160208202803683370190505b50838281518110610e5757610e57613b41565b6020026020010181905250600060096000878785818110610e7a57610e7a613b41565b9050602002016020810190610e8f9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f05576000818152602083905260409020548551869085908110610ed957610ed9613b41565b60200260200101518281518110610ef257610ef2613b41565b6020908102919091010152600101610eae565b5050600101610dfb565b505092915050565b610bc383838360405180602001604052806000815250611771565b6000806000806000610f4386612413565b60008681526008602052604081208054600b80549293929091908110610f6b57610f6b613b41565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbc610fb78484612a93565b612afa565b9392505050565b6000610fcd61219b565b346000610fda8286612a93565b9050610fe581612b2b565b610fef8185612b77565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102890889087908b90613b72565b60405180910390a295945050505050565b61104161219b565b60008060005b848110156110d85785858281811061106157611061613b41565b905060200201359250611073836121e8565b6000838152600860205260409020915061108c826124e0565b611096828561252a565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c891815260200190565b60405180910390a2600101611047565b505050505050565b6110e861219b565b60008060005b8381101561116f5784848281811061110857611108613b41565b90506020020135925061111a836121e8565b6000838152600860205260409020915061113382612c17565b61113c82612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ee565b5050505050565b61117e61219b565b80611188816121e8565b600082815260086020526040902061119f81612c17565b6111a881612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109ce5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b6060816001600160401b038111156112525761125261382f565b60405190808252806020026020018201604052801561128557816020015b60608152602001906001900390816112705790505b5090506000611293600b5490565b905060005b83811015610f0f57816001600160401b038111156112b8576112b861382f565b6040519080825280602002602001820160405280156112e1578160200160208202803683370190505b508382815181106112f4576112f4613b41565b60200260200101819052506000600a600087878581811061131757611317613b41565b905060200201602081019061132c9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a257600081815260208390526040902054855186908590811061137657611376613b41565b6020026020010151828151811061138f5761138f613b41565b602090810291909101015260010161134b565b5050600101611298565b60006001600160a01b0382166114165760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092a565b506001600160a01b031660009081526003602052604090205490565b61143a6129e4565b610d996000612cb9565b60606000821180156114615750600b5461145e8385613baa565b11155b61147d5760405162461bcd60e51b815260040161092a90613bbd565b816001600160401b038111156114955761149561382f565b6040519080825280602002602001820160405280156114ea57816020015b6114d760405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b35790505b50905060005b8281101561157257600b8185018154811061150d5761150d613b41565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155657611556613b41565b602002602001018190525061156b8160010190565b90506114f0565b5092915050565b6115816129e4565b610d99612d0b565b600061159482612413565b60008281526008602052604090206115ab816124e0565b610fbc81612904565b606060018054610a0990613aba565b6115ce338383612d4e565b5050565b6115da61219b565b6000805b8381101561116f578484828181106115f8576115f8613b41565b90506020020135915061160a826121e8565b60008281526008602052604090206116229084612801565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115de565b61167161219b565b8161167b816121e8565b600083815260086020526040902061169281612c17565b8054600b805460009190839081106116ac576116ac613b41565b90600052602060002090600302019050848160000154346116cd9190613baa565b146116ea5760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a6020908152604080832085845290915290208054600019019055600181015461172f9084908790612e1c565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176191815260200190565b60405180910390a2505050505050565b61177b3383612612565b6117975760405162461bcd60e51b815260040161092a90613af4565b6117a384848484612e6c565b50505050565b6117b161219b565b60008060005b848110156110d8578585828181106117d1576117d1613b41565b9050602002013592506117e3836121e8565b600083815260086020526040902060028101549092506118029061223d565b156118475760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092a565b611850836122b1565b61185a8285612354565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b7565b6118a061219b565b600182116118e15760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092a565b3460008080855b8015611a95576000190187878281811061190457611904613b41565b905060200201359350611916846121e8565b6000848152600860205260409020925061192f836124e0565b82546003840154600b805460a09290921b918390811061195157611951613b41565b9060005260206000209060030201935083600101548810156119a85760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b83546119b49088613baa565b96506119c68560010154600019141590565b156119fc576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a29565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3d57611a38866122b1565b611a8e565b6000196001860155611a5085888a612e1c565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a859493929190613c14565b60405180910390a15b50506118e8565b5050505050505050565b6060611aaa82612413565b6000611ac160408051602081019091526000815290565b90506000815111611ae15760405180602001604052806000815250610fbc565b80611aeb84612e9f565b604051602001611afc929190613c5a565b6040516020818303038152906040529392505050565b611b1a6129e4565b81600003611b5e5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092a565b6000828152600c6020908152604080832084845290915290205415611bbd5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092a565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc161219b565b600082118015611cd9575034611cd78387613c89565b145b611cf55760405162461bcd60e51b815260040161092a90613bbd565b6000611d018686612a93565b9050611d0c81612b2b565b600754600101915060005b83811015611d7657611d298286612b77565b611d338184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6693929190613b72565b60405180910390a2600101611d17565b50505b949350505050565b611d8961219b565b81611d93816121e8565b6000838152600860205260409020611daa81612c17565b8054600b80546000919083908110611dc457611dc4613b41565b9060005260206000209060030201905080600101548511611df75760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3890849087612e1c565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176191815260200190565b6000611e7461219b565b34825185611e829190613c89565b14611e9f5760405162461bcd60e51b815260040161092a90613bbd565b6000611eab8585612a93565b9050611eb681612b2b565b600754600101915060005b8351811015611f5357611eed82858381518110611ee057611ee0613b41565b6020026020010151612b77565b611ef78184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2a57611f2a613b41565b60200260200101518888604051611f4393929190613b72565b60405180910390a2600101611ec1565b50509392505050565b611f646129e4565b43600b611f718484612a93565b81548110611f8157611f81613b41565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cab929190918252602082015260400190565b611fd861219b565b60008060005b8381101561116f57848482818110611ff857611ff8613b41565b90506020020135925061200a836121e8565b60008381526008602052604090209150612023826124e0565b61202c82612904565b156120705760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b612079826129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fde565b6120b46129e4565b600019600b6120c38484612a93565b815481106120d3576120d3613b41565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cab929190918252602082015260400190565b61212a6129e4565b6001600160a01b03811661218f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092a565b61219881612cb9565b50565b600654600160a01b900460ff1615610d995760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092a565b6121f1816111d8565b6001600160a01b0316336001600160a01b0316146121985760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092a565b600060001982036122895760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092a565b6000612296600a84613baa565b90504381116122a85750600092915050565b43900392915050565b60006122bc826111d8565b90506122cc816000846001612f31565b6122d5826111d8565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236d5761236d613b41565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123c8576040519150601f19603f3d011682016040523d82523d6000602084013e6123cd565b606091505b50509050806117a35760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092a565b6000818152600260205260409020546001600160a01b03166121985760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a7826111d8565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092a565b8154600383015460a01b61253d84612904565b83101561257f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b60006125af600b848154811061259757612597613b41565b90600052602060002090600302016000015485612a93565b90506125ba81612b2b565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061261e836111d8565b9050806001600160a01b0316846001600160a01b0316148061266557506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d795750836001600160a01b031661267e84610a8c565b6001600160a01b031614949350505050565b826001600160a01b03166126a3826111d8565b6001600160a01b0316146126c95760405162461bcd60e51b815260040161092a90613ca0565b6001600160a01b03821661272b5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092a565b6127388383836001612f31565b826001600160a01b031661274b826111d8565b6001600160a01b0316146127715760405162461bcd60e51b815260040161092a90613ca0565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280a826124e0565b8154600383015460a01b6001600160a01b0319808416908216036128405760405162461bcd60e51b815260040161092a90613be9565b600184015460001914612897576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128dd565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129565760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092a565b6000600b84600001548154811061296f5761296f613b41565b9060005260206000209060030201600101548261298c9190613baa565b905043811161299f575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d995760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092a565b612a46612ffa565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af05760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092a565b6000198101611d79565b600043600b8381548110612b1057612b10613b41565b90600052602060002090600302016002015411159050919050565b612b3481612afa565b6121985760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092a565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115ce90339061304a565b6001810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092a565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1361219b565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a763390565b816001600160a01b0316836001600160a01b031603612daf5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e288383612a93565b9050612e3381612b2b565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e77848484612690565b612e8384848484613064565b6117a35760405162461bcd60e51b815260040161092a90613ce5565b60606000612eac83613162565b60010190506000816001600160401b03811115612ecb57612ecb61382f565b6040519080825280601f01601f191660200182016040528015612ef5576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612eff57509392505050565b80600114612f815760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092a565b6001600160a01b0383161580612fa95750600082815260086020526040902060020154600019145b612ff55760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092a565b6117a3565b600654600160a01b900460ff16610d995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092a565b6115ce82826040518060200160405280600081525061323a565b60006001600160a01b0384163b1561315a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130a8903390899088908890600401613d37565b6020604051808303816000875af19250505080156130e3575060408051601f3d908101601f191682019092526130e091810190613d74565b60015b613140573d808015613111576040519150601f19603f3d011682016040523d82523d6000602084013e613116565b606091505b5080516000036131385760405162461bcd60e51b815260040161092a90613ce5565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d79565b506001611d79565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a15772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cd576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131eb57662386f26fc10000830492506010015b6305f5e1008310613203576305f5e100830492506008015b612710831061321757612710830492506004015b60648310613229576064830492506002015b600a83106109ce5760010192915050565b613244838361326d565b6132516000848484613064565b610bc35760405162461bcd60e51b815260040161092a90613ce5565b6001600160a01b0382166132c35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092a565b6000818152600260205260409020546001600160a01b0316156133285760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b613336600083836001612f31565b6000818152600260205260409020546001600160a01b03161561339b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219857600080fd5b6000806040838503121561342e57600080fd5b82359150602083013561344081613406565b809150509250929050565b6001600160e01b03198116811461219857600080fd5b60006020828403121561347357600080fd5b8135610fbc8161344b565b60006020828403121561349057600080fd5b5035919050565b60005b838110156134b257818101518382015260200161349a565b50506000910152565b600081518084526134d3816020860160208601613497565b601f01601f19169290920160200192915050565b602081526000610fbc60208301846134bb565b6000806040838503121561350d57600080fd5b823561351881613406565b946020939093013593505050565b6000806040838503121561353957600080fd5b50508035926020909101359150565b60008060006060848603121561355d57600080fd5b833561356881613406565b9250602084013561357881613406565b929592945050506040919091013590565b80356001600160a01b0319811681146135a157600080fd5b919050565b600080604083850312156135b957600080fd5b823591506135c960208401613589565b90509250929050565b60008083601f8401126135e457600080fd5b5081356001600160401b038111156135fb57600080fd5b6020830191508360208260051b850101111561361657600080fd5b9250929050565b6000806020838503121561363057600080fd5b82356001600160401b0381111561364657600080fd5b613652858286016135d2565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136da57888603603f19018552825180518088529088019088880190845b818110156136c45783518352928a0192918a01916001016136a8565b5090975050509386019391860191600101613686565b509398975050505050505050565b6000806000604084860312156136fd57600080fd5b83356001600160401b0381111561371357600080fd5b61371f868287016135d2565b909790965060209590950135949350505050565b60006020828403121561374557600080fd5b8135610fbc81613406565b602080825282518282018190526000919060409081850190868401855b8281101561379c578151805185528681015187860152850151858501526060909301929085019060010161376d565b5091979650505050505050565b600080604083850312156137bc57600080fd5b82356137c781613406565b91506020830135801515811461344057600080fd5b6000806000604084860312156137f157600080fd5b83356001600160401b0381111561380757600080fd5b613813868287016135d2565b9094509250613826905060208501613589565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386d5761386d61382f565b604052919050565b6000806000806080858703121561388b57600080fd5b843561389681613406565b93506020858101356138a781613406565b93506040860135925060608601356001600160401b03808211156138ca57600080fd5b818801915088601f8301126138de57600080fd5b8135818111156138f0576138f061382f565b613902601f8201601f19168501613845565b9150808252898482850101111561391857600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394d57600080fd5b83356001600160401b0381111561396357600080fd5b61396f868287016135d2565b909450925050602084013561398381613406565b809150509250925092565b600080600080608085870312156139a457600080fd5b84359350602085013592506139bb60408601613589565b9396929550929360600135925050565b6000806000606084860312156139e057600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0657600080fd5b818701915087601f830112613a1a57600080fd5b813581811115613a2c57613a2c61382f565b8060051b9150613a3d848301613845565b818152918301840191848101908a841115613a5757600080fd5b938501935b83851015613a7c57613a6d85613589565b82529385019390850190613a5c565b8096505050505050509250925092565b60008060408385031215613a9f57600080fd5b8235613aaa81613406565b9150602083013561344081613406565b600181811c90821680613ace57607f821691505b602082108103613aee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6957600080fd5b610fbc82613589565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109ce576109ce613b94565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3457600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6c818460208801613497565b835190830190613c80818360208801613497565b01949350505050565b80820281158282048414176109ce576109ce613b94565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6a908301846134bb565b9695505050505050565b600060208284031215613d8657600080fd5b8151610fbc8161344b56fea264697066735822122033a72ba2419a7cb3b00b4b4de4305d6458e98ea74f8be8cc9c16afc85a97571764736f6c63430008130033` + _liquidStakingContractABI = `[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "AmountIncreased", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "BucketTypeDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes12", + "name": "newDelegate", + "type": "bytes12" + } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "DurationExtended", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Locked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Merged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes12", + "name": "delegate", + "type": "bytes12" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unlocked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Unstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "Withdrawal", + "type": "event" + }, + { + "inputs": [], + "name": "UINT256_MAX", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "UNSTAKE_FREEZE_BLOCKS", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "activateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "addBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToUnstake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "blocksToWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "bucketOf", + "outputs": [ + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unlockedAt_", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "unstakedAt_", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "delegate_", + "type": "bytes12" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_offset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_size", + "type": "uint256" + } + ], + "name": "bucketTypes", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activatedAt", + "type": "uint256" + } + ], + "internalType": "struct BucketType[]", + "name": "types_", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "changeDelegates", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "deactivateBucketType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" + } + ], + "name": "extendDuration", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_newAmount", + "type": "uint256" + } + ], + "name": "increaseAmount", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "isActiveBucketType", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + } + ], + "name": "lock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "lockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_newDuration", + "type": "uint256" + } + ], + "name": "merge", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numOfBucketTypes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12", + "name": "_delegate", + "type": "bytes12" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "stake", + "outputs": [ + { + "internalType": "uint256", + "name": "firstTokenId_", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes12[]", + "name": "_delegates", + "type": "bytes12[]" + } + ], + "name": "unlockedVotesTo", + "outputs": [ + { + "internalType": "uint256[][]", + "name": "counts_", + "type": "uint256[][]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + } + ], + "name": "unstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_tokenId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "_tokenIds", + "type": "uint256[]" + }, + { + "internalType": "address payable", + "name": "_recipient", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ]` ) func TestLiquidStaking(t *testing.T) { @@ -66,7 +1297,7 @@ func TestLiquidStaking(t *testing.T) { sk: identityset.PrivateKey(1), } contractAddresses := deployContracts(bc, sf, dao, ap, ¶m, r) - lsdABI, err := abi.JSON(strings.NewReader(blockindex.LiquidStakingContractABI)) + lsdABI, err := abi.JSON(strings.NewReader(_liquidStakingContractABI)) r.NoError(err) // init bucket type @@ -119,7 +1350,7 @@ func TestLiquidStaking(t *testing.T) { receipts, blk := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - buckets, err := indexer.GetBuckets() + buckets, err := indexer.Buckets() r.NoError(err) slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { return i.Index < j.Index @@ -135,7 +1366,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(blk.Timestamp().UTC(), bt.CreateTime) r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) r.EqualValues(time.Unix(0, 0).UTC(), bt.UnstakeStartTime) - r.EqualValues(10, indexer.GetCandidateVotes("delegate2").Int64()) + r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) @@ -152,10 +1383,10 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err := indexer.GetBucket(uint64(tokenID)) + bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) - r.EqualValues(10, indexer.GetCandidateVotes("delegate2").Int64()) + r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) t.Run("unstake", func(t *testing.T) { jumpBlocks(bc, 10, r) @@ -173,10 +1404,10 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err := indexer.GetBucket(uint64(tokenID)) + bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC(), bt.UnstakeStartTime) - r.EqualValues(0, indexer.GetCandidateVotes("delegate2").Int64()) + r.EqualValues(0, indexer.CandidateVotes("delegate2").Int64()) t.Run("withdraw", func(t *testing.T) { // freeze blocks are changed to 10 in test @@ -198,7 +1429,7 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) + bt, err = indexer.Bucket(uint64(tokenID)) r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) }) }) @@ -238,7 +1469,7 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) + bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) r.True(bt.AutoStake) }) @@ -266,7 +1497,7 @@ func TestLiquidStaking(t *testing.T) { for _, receipt := range receipts { r.EqualValues(iotextypes.ReceiptStatus_Success, receipt.Status) } - buckets, err := indexer.GetBuckets() + buckets, err := indexer.Buckets() r.NoError(err) slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { return i.Index < j.Index @@ -294,11 +1525,11 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) for i := range newBuckets { if i == 0 { - bt, err := indexer.GetBucket(uint64(newBuckets[i].Index)) + bt, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.NoError(err) r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) } else { - _, err := indexer.GetBucket(uint64(newBuckets[i].Index)) + _, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) } } @@ -323,7 +1554,7 @@ func TestLiquidStaking(t *testing.T) { receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) + bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) }) @@ -346,7 +1577,7 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) + bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(100, bt.StakedAmount.Int64()) }) @@ -372,7 +1603,7 @@ func TestLiquidStaking(t *testing.T) { r.Len(receipts, 1) r.EqualValues("", receipts[0].ExecutionRevertMsg()) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - bt, err = indexer.GetBucket(uint64(tokenID)) + bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues("delegate6", bt.Candidate) }) @@ -608,7 +1839,7 @@ func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blo receipts, _ := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) - buckets, err := indexer.GetBuckets() + buckets, err := indexer.Buckets() r.NoError(err) slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { return i.Index < j.Index From 901d768b20418110d467cb71f68c95aeb83c99fd Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 28 Apr 2023 15:32:22 +0800 Subject: [PATCH 23/51] split the big indexer file by struct --- blockindex/liquidstaking_bucket.go | 156 ++++++++++++ blockindex/liquidstaking_cache.go | 165 ++++++++++++ blockindex/liquidstaking_indexer.go | 375 ---------------------------- blockindex/util.go | 103 ++++++++ 4 files changed, 424 insertions(+), 375 deletions(-) create mode 100644 blockindex/liquidstaking_bucket.go create mode 100644 blockindex/liquidstaking_cache.go create mode 100644 blockindex/util.go diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go new file mode 100644 index 0000000000..bd49660dc6 --- /dev/null +++ b/blockindex/liquidstaking_bucket.go @@ -0,0 +1,156 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "math/big" + "time" + + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/blockindex/indexpb" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type ( + // BucketInfo is the bucket information + BucketInfo struct { + TypeIndex uint64 + CreatedAt time.Time + UnlockedAt *time.Time + UnstakedAt *time.Time + Delegate string + Owner string + } + + // BucketType is the bucket type + BucketType struct { + Amount *big.Int + Duration time.Duration + ActivatedAt *time.Time + } + + // Bucket is the bucket information including bucket type and bucket info + Bucket struct { + Index uint64 + Candidate string + Owner address.Address + StakedAmount *big.Int + StakedDuration time.Duration + CreateTime time.Time + StakeStartTime time.Time + UnstakeStartTime time.Time + AutoStake bool + } +) + +func (bt *BucketType) toProto() *indexpb.BucketType { + return &indexpb.BucketType{ + Amount: bt.Amount.String(), + Duration: uint64(bt.Duration), + ActivatedAt: timestamppb.New(*bt.ActivatedAt), + } +} + +func (bt *BucketType) loadProto(p *indexpb.BucketType) error { + var ok bool + bt.Amount, ok = big.NewInt(0).SetString(p.Amount, 10) + if !ok { + return errors.New("failed to parse amount") + } + bt.Duration = time.Duration(p.Duration) + t := p.ActivatedAt.AsTime() + bt.ActivatedAt = &t + return nil +} + +func (bt *BucketType) serialize() []byte { + return byteutil.Must(proto.Marshal(bt.toProto())) +} + +func (bt *BucketType) deserialize(b []byte) error { + m := indexpb.BucketType{} + if err := proto.Unmarshal(b, &m); err != nil { + return err + } + return bt.loadProto(&m) +} + +func (bi *BucketInfo) toProto() *indexpb.BucketInfo { + pb := &indexpb.BucketInfo{ + TypeIndex: bi.TypeIndex, + Delegate: bi.Delegate, + CreatedAt: timestamppb.New(bi.CreatedAt), + Owner: bi.Owner, + } + if bi.UnlockedAt != nil { + pb.UnlockedAt = timestamppb.New(*bi.UnlockedAt) + } + if bi.UnstakedAt != nil { + pb.UnstakedAt = timestamppb.New(*bi.UnstakedAt) + } + return pb +} + +func (bi *BucketInfo) serialize() []byte { + return byteutil.Must(proto.Marshal(bi.toProto())) +} + +func (bi *BucketInfo) deserialize(b []byte) error { + m := indexpb.BucketInfo{} + if err := proto.Unmarshal(b, &m); err != nil { + return err + } + return bi.loadProto(&m) +} + +func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { + bi.TypeIndex = p.TypeIndex + bi.CreatedAt = p.CreatedAt.AsTime() + if p.UnlockedAt != nil { + t := p.UnlockedAt.AsTime() + bi.UnlockedAt = &t + } else { + bi.UnlockedAt = nil + } + if p.UnstakedAt != nil { + t := p.UnstakedAt.AsTime() + bi.UnstakedAt = &t + } else { + bi.UnstakedAt = nil + } + bi.Delegate = p.Delegate + bi.Owner = p.Owner + return nil +} + +func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { + var err error + vb := Bucket{ + Index: token, + StakedAmount: bt.Amount, + StakedDuration: bt.Duration, + CreateTime: bi.CreatedAt, + StakeStartTime: bi.CreatedAt, + UnstakeStartTime: time.Unix(0, 0).UTC(), + AutoStake: bi.UnlockedAt == nil, + Candidate: bi.Delegate, + } + + vb.Owner, err = address.FromHex(bi.Owner) + if err != nil { + return nil, err + } + if bi.UnlockedAt != nil { + vb.StakeStartTime = *bi.UnlockedAt + } + if bi.UnstakedAt != nil { + vb.UnstakeStartTime = *bi.UnstakedAt + } + return &vb, nil +} diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go new file mode 100644 index 0000000000..e697d04cd0 --- /dev/null +++ b/blockindex/liquidstaking_cache.go @@ -0,0 +1,165 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "math/big" + "time" + + "github.com/iotexproject/iotex-core/db/batch" +) + +type ( + liquidStakingCache struct { + idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo + candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket + idBucketTypeMap map[uint64]*BucketType // map[token]BucketType + propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + height uint64 + } +) + +func newLiquidStakingCache() *liquidStakingCache { + return &liquidStakingCache{ + idBucketMap: make(map[uint64]*BucketInfo), + idBucketTypeMap: make(map[uint64]*BucketType), + propertyBucketTypeMap: make(map[int64]map[int64]uint64), + candidateBucketMap: make(map[string]map[uint64]bool), + } +} + +func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { + for i := 0; i < b.Size(); i++ { + write, err := b.Entry(i) + if err != nil { + return err + } + switch write.Namespace() { + case _liquidStakingBucketInfoNS: + if write.WriteType() == batch.Put { + var bi BucketInfo + if err = bi.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketInfo(id, &bi) + } else if write.WriteType() == batch.Delete { + id := deserializeUint64(write.Key()) + s.deleteBucketInfo(id) + } + case _liquidStakingBucketTypeNS: + if write.WriteType() == batch.Put { + var bt BucketType + if err = bt.deserialize(write.Value()); err != nil { + return err + } + id := deserializeUint64(write.Key()) + s.putBucketType(id, &bt) + } + } + } + return nil +} + +func (s *liquidStakingCache) putHeight(h uint64) { + s.height = h +} + +func (s *liquidStakingCache) getHeight() uint64 { + return s.height +} + +func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { + amount := bt.Amount.Int64() + s.idBucketTypeMap[id] = bt + m, ok := s.propertyBucketTypeMap[amount] + if !ok { + s.propertyBucketTypeMap[amount] = make(map[int64]uint64) + m = s.propertyBucketTypeMap[amount] + } + m[int64(bt.Duration)] = id +} + +func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { + s.idBucketMap[id] = bi + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) + } + s.candidateBucketMap[bi.Delegate][id] = true +} + +func (s *liquidStakingCache) deleteBucketInfo(id uint64) { + bi, ok := s.idBucketMap[id] + if !ok { + return + } + delete(s.idBucketMap, id) + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + return + } + delete(s.candidateBucketMap[bi.Delegate], id) +} + +func (s *liquidStakingCache) markDeleteBucketInfo(id uint64) { + bi, ok := s.idBucketMap[id] + if !ok { + return + } + s.idBucketMap[id] = nil + if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + return + } + s.candidateBucketMap[bi.Delegate][id] = false +} + +func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + m, ok := s.propertyBucketTypeMap[amount.Int64()] + if !ok { + return 0, false + } + id, ok := m[int64(duration)] + return id, ok +} + +func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.idBucketTypeMap[id] + return bt, ok +} + +func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { + bt, ok := s.idBucketTypeMap[id] + if !ok { + panic("bucket type not found") + } + return bt +} + +func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { + bi, ok := s.idBucketMap[id] + return bi, ok +} + +func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { + votes := big.NewInt(0) + m, ok := s.candidateBucketMap[name] + if !ok { + return votes + } + for k, v := range m { + if v { + bi, ok := s.idBucketMap[k] + if !ok { + continue + } + if bi.UnstakedAt != nil { + continue + } + bt := s.mustGetBucketType(bi.TypeIndex) + votes.Add(votes, bt.Amount) + } + } + return votes +} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index e92cb76d19..257632854f 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -7,7 +7,6 @@ package blockindex import ( "context" - "encoding/binary" "math/big" "strings" "time" @@ -15,18 +14,13 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "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/blockdao" - "github.com/iotexproject/iotex-core/blockindex/indexpb" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/db/batch" - "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/timestamppb" ) const ( @@ -397,55 +391,12 @@ type ( tokenOwner map[uint64]string // token id -> owner blockInterval time.Duration } - - // BucketInfo is the bucket information - BucketInfo struct { - TypeIndex uint64 - CreatedAt time.Time - UnlockedAt *time.Time - UnstakedAt *time.Time - Delegate string - Owner string - } - - // BucketType is the bucket type - BucketType struct { - Amount *big.Int - Duration time.Duration - ActivatedAt *time.Time - } - - // Bucket is the bucket information including bucket type and bucket info - Bucket struct { - Index uint64 - Candidate string - Owner address.Address - StakedAmount *big.Int - StakedDuration time.Duration - CreateTime time.Time - StakeStartTime time.Time - UnstakeStartTime time.Time - AutoStake bool - } - - // eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type - // TODO: this is general enough to be moved to a common package - eventParam map[string]any - - liquidStakingCache struct { - idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo - candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket - idBucketTypeMap map[uint64]*BucketType // map[token]BucketType - propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index - height uint64 - } ) var ( _liquidStakingInterface abi.ABI _liquidStakingHeightKey = []byte("lsHeight") - errInvlidEventParam = errors.New("invalid event param") errBucketTypeNotExist = errors.New("bucket type does not exist") // ErrBucketInfoNotExist is the error when bucket does not exist @@ -997,329 +948,3 @@ func (s *liquidStakingIndexer) commit() error { func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { return time.Duration(height) * s.blockInterval } - -func eventField[T any](e eventParam, name string) (T, error) { - field, ok := e[name].(T) - if !ok { - return field, errors.Wrapf(errInvlidEventParam, "field %s got %#v, expect %T", name, e[name], field) - } - return field, nil -} - -func (e eventParam) fieldUint256(name string) (*big.Int, error) { - return eventField[*big.Int](e, name) -} - -func (e eventParam) fieldBytes12(name string) (string, error) { - data, err := eventField[[12]byte](e, name) - if err != nil { - return "", err - } - // remove trailing zeros - tail := len(data) - 1 - for ; tail >= 0 && data[tail] == 0; tail-- { - } - return string(data[:tail+1]), nil -} - -func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { - return eventField[[]*big.Int](e, name) -} - -func (e eventParam) fieldAddress(name string) (common.Address, error) { - return eventField[common.Address](e, name) -} - -func (e eventParam) indexedFieldAddress(name string) (common.Address, error) { - return eventField[common.Address](e, name) -} - -func (e eventParam) indexedFieldUint256(name string) (*big.Int, error) { - return eventField[*big.Int](e, name) -} - -func (bt *BucketType) toProto() *indexpb.BucketType { - return &indexpb.BucketType{ - Amount: bt.Amount.String(), - Duration: uint64(bt.Duration), - ActivatedAt: timestamppb.New(*bt.ActivatedAt), - } -} - -func (bt *BucketType) loadProto(p *indexpb.BucketType) error { - var ok bool - bt.Amount, ok = big.NewInt(0).SetString(p.Amount, 10) - if !ok { - return errors.New("failed to parse amount") - } - bt.Duration = time.Duration(p.Duration) - t := p.ActivatedAt.AsTime() - bt.ActivatedAt = &t - return nil -} - -func (bt *BucketType) serialize() []byte { - return byteutil.Must(proto.Marshal(bt.toProto())) -} - -func (bt *BucketType) deserialize(b []byte) error { - m := indexpb.BucketType{} - if err := proto.Unmarshal(b, &m); err != nil { - return err - } - return bt.loadProto(&m) -} - -func (bi *BucketInfo) toProto() *indexpb.BucketInfo { - pb := &indexpb.BucketInfo{ - TypeIndex: bi.TypeIndex, - Delegate: bi.Delegate, - CreatedAt: timestamppb.New(bi.CreatedAt), - Owner: bi.Owner, - } - if bi.UnlockedAt != nil { - pb.UnlockedAt = timestamppb.New(*bi.UnlockedAt) - } - if bi.UnstakedAt != nil { - pb.UnstakedAt = timestamppb.New(*bi.UnstakedAt) - } - return pb -} - -func (bi *BucketInfo) serialize() []byte { - return byteutil.Must(proto.Marshal(bi.toProto())) -} - -func (bi *BucketInfo) deserialize(b []byte) error { - m := indexpb.BucketInfo{} - if err := proto.Unmarshal(b, &m); err != nil { - return err - } - return bi.loadProto(&m) -} - -func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { - bi.TypeIndex = p.TypeIndex - bi.CreatedAt = p.CreatedAt.AsTime() - if p.UnlockedAt != nil { - t := p.UnlockedAt.AsTime() - bi.UnlockedAt = &t - } else { - bi.UnlockedAt = nil - } - if p.UnstakedAt != nil { - t := p.UnstakedAt.AsTime() - bi.UnstakedAt = &t - } else { - bi.UnstakedAt = nil - } - bi.Delegate = p.Delegate - bi.Owner = p.Owner - return nil -} - -func newLiquidStakingCache() *liquidStakingCache { - return &liquidStakingCache{ - idBucketMap: make(map[uint64]*BucketInfo), - idBucketTypeMap: make(map[uint64]*BucketType), - propertyBucketTypeMap: make(map[int64]map[int64]uint64), - candidateBucketMap: make(map[string]map[uint64]bool), - } -} - -func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { - for i := 0; i < b.Size(); i++ { - write, err := b.Entry(i) - if err != nil { - return err - } - switch write.Namespace() { - case _liquidStakingBucketInfoNS: - if write.WriteType() == batch.Put { - var bi BucketInfo - if err = bi.deserialize(write.Value()); err != nil { - return err - } - id := deserializeUint64(write.Key()) - s.putBucketInfo(id, &bi) - } else if write.WriteType() == batch.Delete { - id := deserializeUint64(write.Key()) - s.deleteBucketInfo(id) - } - case _liquidStakingBucketTypeNS: - if write.WriteType() == batch.Put { - var bt BucketType - if err = bt.deserialize(write.Value()); err != nil { - return err - } - id := deserializeUint64(write.Key()) - s.putBucketType(id, &bt) - } - } - } - return nil -} - -func (s *liquidStakingCache) putHeight(h uint64) { - s.height = h -} - -func (s *liquidStakingCache) getHeight() uint64 { - return s.height -} - -func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { - amount := bt.Amount.Int64() - s.idBucketTypeMap[id] = bt - m, ok := s.propertyBucketTypeMap[amount] - if !ok { - s.propertyBucketTypeMap[amount] = make(map[int64]uint64) - m = s.propertyBucketTypeMap[amount] - } - m[int64(bt.Duration)] = id -} - -func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { - s.idBucketMap[id] = bi - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) - } - s.candidateBucketMap[bi.Delegate][id] = true -} - -func (s *liquidStakingCache) deleteBucketInfo(id uint64) { - bi, ok := s.idBucketMap[id] - if !ok { - return - } - delete(s.idBucketMap, id) - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - return - } - delete(s.candidateBucketMap[bi.Delegate], id) -} - -func (s *liquidStakingCache) markDeleteBucketInfo(id uint64) { - bi, ok := s.idBucketMap[id] - if !ok { - return - } - s.idBucketMap[id] = nil - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - return - } - s.candidateBucketMap[bi.Delegate][id] = false -} - -func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - m, ok := s.propertyBucketTypeMap[amount.Int64()] - if !ok { - return 0, false - } - id, ok := m[int64(duration)] - return id, ok -} - -func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.idBucketTypeMap[id] - return bt, ok -} - -func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { - bt, ok := s.idBucketTypeMap[id] - if !ok { - panic("bucket type not found") - } - return bt -} - -func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.idBucketMap[id] - return bi, ok -} - -func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { - votes := big.NewInt(0) - m, ok := s.candidateBucketMap[name] - if !ok { - return votes - } - for k, v := range m { - if v { - bi, ok := s.idBucketMap[k] - if !ok { - continue - } - if bi.UnstakedAt != nil { - continue - } - bt := s.mustGetBucketType(bi.TypeIndex) - votes.Add(votes, bt.Amount) - } - } - return votes -} - -func serializeUint64(v uint64) []byte { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, v) - return b -} - -func deserializeUint64(b []byte) uint64 { - return binary.LittleEndian.Uint64(b) -} - -func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { - var err error - vb := Bucket{ - Index: token, - StakedAmount: bt.Amount, - StakedDuration: bt.Duration, - CreateTime: bi.CreatedAt, - StakeStartTime: bi.CreatedAt, - UnstakeStartTime: time.Unix(0, 0).UTC(), - AutoStake: bi.UnlockedAt == nil, - Candidate: bi.Delegate, - } - - vb.Owner, err = address.FromHex(bi.Owner) - if err != nil { - return nil, err - } - if bi.UnlockedAt != nil { - vb.StakeStartTime = *bi.UnlockedAt - } - if bi.UnstakedAt != nil { - vb.UnstakeStartTime = *bi.UnstakedAt - } - return &vb, nil -} - -func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) { - event := make(eventParam) - // unpack non-indexed fields - if len(log.Data) > 0 { - if err := abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { - return nil, errors.Wrap(err, "unpack event data failed") - } - } - // unpack indexed fields - args := make(abi.Arguments, 0) - for _, arg := range abiEvent.Inputs { - if arg.Indexed { - args = append(args, arg) - } - } - topics := make([]common.Hash, 0) - for i, topic := range log.Topics { - if i > 0 { - topics = append(topics, common.Hash(topic)) - } - } - err := abi.ParseTopicsIntoMap(event, args, topics) - if err != nil { - return nil, errors.Wrap(err, "unpack event indexed fields failed") - } - return event, nil -} diff --git a/blockindex/util.go b/blockindex/util.go new file mode 100644 index 0000000000..09e4c87ff2 --- /dev/null +++ b/blockindex/util.go @@ -0,0 +1,103 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "encoding/binary" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/iotexproject/iotex-core/action" + "github.com/pkg/errors" +) + +type ( + // eventParam is a struct to hold smart contract event parameters, which can easily convert a param to go type + eventParam map[string]any +) + +var ( + errInvlidEventParam = errors.New("invalid event param") +) + +func eventField[T any](e eventParam, name string) (T, error) { + field, ok := e[name].(T) + if !ok { + return field, errors.Wrapf(errInvlidEventParam, "field %s got %#v, expect %T", name, e[name], field) + } + return field, nil +} + +func (e eventParam) fieldUint256(name string) (*big.Int, error) { + return eventField[*big.Int](e, name) +} + +func (e eventParam) fieldBytes12(name string) (string, error) { + data, err := eventField[[12]byte](e, name) + if err != nil { + return "", err + } + // remove trailing zeros + tail := len(data) - 1 + for ; tail >= 0 && data[tail] == 0; tail-- { + } + return string(data[:tail+1]), nil +} + +func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { + return eventField[[]*big.Int](e, name) +} + +func (e eventParam) fieldAddress(name string) (common.Address, error) { + return eventField[common.Address](e, name) +} + +func (e eventParam) indexedFieldAddress(name string) (common.Address, error) { + return eventField[common.Address](e, name) +} + +func (e eventParam) indexedFieldUint256(name string) (*big.Int, error) { + return eventField[*big.Int](e, name) +} + +func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) { + event := make(eventParam) + // unpack non-indexed fields + if len(log.Data) > 0 { + if err := abiEvent.Inputs.UnpackIntoMap(event, log.Data); err != nil { + return nil, errors.Wrap(err, "unpack event data failed") + } + } + // unpack indexed fields + args := make(abi.Arguments, 0) + for _, arg := range abiEvent.Inputs { + if arg.Indexed { + args = append(args, arg) + } + } + topics := make([]common.Hash, 0) + for i, topic := range log.Topics { + if i > 0 { + topics = append(topics, common.Hash(topic)) + } + } + err := abi.ParseTopicsIntoMap(event, args, topics) + if err != nil { + return nil, errors.Wrap(err, "unpack event indexed fields failed") + } + return event, nil +} + +func serializeUint64(v uint64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, v) + return b +} + +func deserializeUint64(b []byte) uint64 { + return binary.LittleEndian.Uint64(b) +} From 6c1fb8c71483fe8e658506d43ccea0493adf400d Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 4 May 2023 11:02:41 +0800 Subject: [PATCH 24/51] replace key encode/decode func with existed in byteutil --- blockindex/liquidstaking_cache.go | 7 ++++--- blockindex/liquidstaking_indexer.go | 16 +++++++++------- blockindex/util.go | 11 ----------- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index e697d04cd0..578aa74e32 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -10,6 +10,7 @@ import ( "time" "github.com/iotexproject/iotex-core/db/batch" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) type ( @@ -44,10 +45,10 @@ func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { if err = bi.deserialize(write.Value()); err != nil { return err } - id := deserializeUint64(write.Key()) + id := byteutil.BytesToUint64BigEndian(write.Key()) s.putBucketInfo(id, &bi) } else if write.WriteType() == batch.Delete { - id := deserializeUint64(write.Key()) + id := byteutil.BytesToUint64BigEndian(write.Key()) s.deleteBucketInfo(id) } case _liquidStakingBucketTypeNS: @@ -56,7 +57,7 @@ func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { if err = bt.deserialize(write.Value()); err != nil { return err } - id := deserializeUint64(write.Key()) + id := byteutil.BytesToUint64BigEndian(write.Key()) s.putBucketType(id, &bt) } } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 257632854f..3e737e1d23 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -19,6 +19,7 @@ import ( "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/db/batch" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" ) @@ -835,7 +836,8 @@ func (s *liquidStakingIndexer) loadCache() error { } height = 0 } else { - height = deserializeUint64(h) + height = byteutil.BytesToUint64BigEndian(h) + } s.cleanCache.putHeight(height) @@ -851,7 +853,7 @@ func (s *liquidStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - s.cleanCache.putBucketInfo(deserializeUint64(ks[i]), &b) + s.cleanCache.putBucketInfo(byteutil.BytesToUint64BigEndian(ks[i]), &b) } // load bucket type @@ -866,7 +868,7 @@ func (s *liquidStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - s.cleanCache.putBucketType(deserializeUint64(ks[i]), &b) + s.cleanCache.putBucketType(byteutil.BytesToUint64BigEndian(ks[i]), &b) } return nil } @@ -904,17 +906,17 @@ func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { } func (s *liquidStakingIndexer) putHeight(h uint64) { - s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, serializeUint64(h), "failed to put height") + s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") s.dirtyCache.putHeight(h) } func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { - s.dirty.Put(_liquidStakingBucketTypeNS, serializeUint64(id), bt.serialize(), "failed to put bucket type") + s.dirty.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") s.dirtyCache.putBucketType(id, bt) } func (s *liquidStakingIndexer) putBucketInfo(id uint64, bi *BucketInfo) { - s.dirty.Put(_liquidStakingBucketInfoNS, serializeUint64(id), bi.serialize(), "failed to put bucket info") + s.dirty.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") s.dirtyCache.putBucketInfo(id, bi) } @@ -928,7 +930,7 @@ func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { } func (s *liquidStakingIndexer) burnBucket(id uint64) { - s.dirty.Delete(_liquidStakingBucketInfoNS, serializeUint64(id), "failed to delete bucket info") + s.dirty.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") s.dirtyCache.markDeleteBucketInfo(id) } diff --git a/blockindex/util.go b/blockindex/util.go index 09e4c87ff2..e2f8c60463 100644 --- a/blockindex/util.go +++ b/blockindex/util.go @@ -6,7 +6,6 @@ package blockindex import ( - "encoding/binary" "math/big" "github.com/ethereum/go-ethereum/accounts/abi" @@ -91,13 +90,3 @@ func unpackEventParam(abiEvent *abi.Event, log *action.Log) (eventParam, error) } return event, nil } - -func serializeUint64(v uint64) []byte { - b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, v) - return b -} - -func deserializeUint64(b []byte) uint64 { - return binary.LittleEndian.Uint64(b) -} From 0fe39adce063d263b9d4436f782fb10ed317c53b Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 4 May 2023 11:31:24 +0800 Subject: [PATCH 25/51] not use pointer of time.Time --- blockindex/indexpb/liquidstaking_bucket.proto | 2 +- blockindex/liquidstaking_bucket.go | 41 ++++++++----------- blockindex/liquidstaking_cache.go | 2 +- blockindex/liquidstaking_indexer.go | 12 +++--- e2etest/liquid_staking_test.go | 3 +- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/blockindex/indexpb/liquidstaking_bucket.proto b/blockindex/indexpb/liquidstaking_bucket.proto index 10afd0ec14..47e580aa33 100644 --- a/blockindex/indexpb/liquidstaking_bucket.proto +++ b/blockindex/indexpb/liquidstaking_bucket.proto @@ -23,4 +23,4 @@ message BucketInfo { google.protobuf.Timestamp unstakedAt = 4; string delegate = 5; string owner = 6; -} \ No newline at end of file +} diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index bd49660dc6..6a1b1223e5 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -22,8 +22,8 @@ type ( BucketInfo struct { TypeIndex uint64 CreatedAt time.Time - UnlockedAt *time.Time - UnstakedAt *time.Time + UnlockedAt time.Time + UnstakedAt time.Time Delegate string Owner string } @@ -32,7 +32,7 @@ type ( BucketType struct { Amount *big.Int Duration time.Duration - ActivatedAt *time.Time + ActivatedAt time.Time } // Bucket is the bucket information including bucket type and bucket info @@ -53,7 +53,7 @@ func (bt *BucketType) toProto() *indexpb.BucketType { return &indexpb.BucketType{ Amount: bt.Amount.String(), Duration: uint64(bt.Duration), - ActivatedAt: timestamppb.New(*bt.ActivatedAt), + ActivatedAt: timestamppb.New(bt.ActivatedAt), } } @@ -64,8 +64,7 @@ func (bt *BucketType) loadProto(p *indexpb.BucketType) error { return errors.New("failed to parse amount") } bt.Duration = time.Duration(p.Duration) - t := p.ActivatedAt.AsTime() - bt.ActivatedAt = &t + bt.ActivatedAt = p.ActivatedAt.AsTime() return nil } @@ -88,11 +87,12 @@ func (bi *BucketInfo) toProto() *indexpb.BucketInfo { CreatedAt: timestamppb.New(bi.CreatedAt), Owner: bi.Owner, } - if bi.UnlockedAt != nil { - pb.UnlockedAt = timestamppb.New(*bi.UnlockedAt) + if !bi.UnlockedAt.IsZero() { + pb.UnlockedAt = timestamppb.New(bi.UnlockedAt) } - if bi.UnstakedAt != nil { - pb.UnstakedAt = timestamppb.New(*bi.UnstakedAt) + time.Unix(0, 0).UTC() + if !bi.UnstakedAt.IsZero() { + pb.UnstakedAt = timestamppb.New(bi.UnstakedAt) } return pb } @@ -113,16 +113,14 @@ func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { bi.TypeIndex = p.TypeIndex bi.CreatedAt = p.CreatedAt.AsTime() if p.UnlockedAt != nil { - t := p.UnlockedAt.AsTime() - bi.UnlockedAt = &t + bi.UnlockedAt = p.UnlockedAt.AsTime() } else { - bi.UnlockedAt = nil + bi.UnlockedAt = time.Time{} } if p.UnstakedAt != nil { - t := p.UnstakedAt.AsTime() - bi.UnstakedAt = &t + bi.UnstakedAt = p.UnstakedAt.AsTime() } else { - bi.UnstakedAt = nil + bi.UnstakedAt = time.Time{} } bi.Delegate = p.Delegate bi.Owner = p.Owner @@ -137,8 +135,8 @@ func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, StakedDuration: bt.Duration, CreateTime: bi.CreatedAt, StakeStartTime: bi.CreatedAt, - UnstakeStartTime: time.Unix(0, 0).UTC(), - AutoStake: bi.UnlockedAt == nil, + UnstakeStartTime: bi.UnstakedAt, + AutoStake: bi.UnlockedAt.IsZero(), Candidate: bi.Delegate, } @@ -146,11 +144,8 @@ func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, if err != nil { return nil, err } - if bi.UnlockedAt != nil { - vb.StakeStartTime = *bi.UnlockedAt - } - if bi.UnstakedAt != nil { - vb.UnstakeStartTime = *bi.UnstakedAt + if !bi.UnlockedAt.IsZero() { + vb.StakeStartTime = bi.UnlockedAt } return &vb, nil } diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 578aa74e32..a14f6c1aaa 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -155,7 +155,7 @@ func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { if !ok { continue } - if bi.UnstakedAt != nil { + if !bi.UnstakedAt.IsZero() { continue } bt := s.mustGetBucketType(bi.TypeIndex) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 3e737e1d23..d0c3861206 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -587,7 +587,7 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, bt := BucketType{ Amount: amountParam, Duration: s.blockHeightToDuration(durationParam.Uint64()), - ActivatedAt: &timeStamp, + ActivatedAt: timeStamp, } id, ok := s.getBucketTypeIndex(amountParam, bt.Duration) if !ok { @@ -615,7 +615,7 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } - bt.ActivatedAt = nil + bt.ActivatedAt = time.Time{} s.putBucketType(id, bt) return nil } @@ -676,7 +676,7 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) } b.TypeIndex = newBtIdx - b.UnlockedAt = nil + b.UnlockedAt = time.Time{} s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -691,7 +691,7 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp t if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - b.UnlockedAt = ×tamp + b.UnlockedAt = timestamp s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -706,7 +706,7 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp t if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - b.UnstakedAt = ×tamp + b.UnstakedAt = timestamp s.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -735,7 +735,7 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx - b.UnlockedAt = nil + b.UnlockedAt = time.Time{} for i := 1; i < len(tokenIDsParam); i++ { s.burnBucket(tokenIDsParam[i].Uint64()) } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 0062851e35..66b937b33d 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -6,7 +6,6 @@ import ( "math/big" "strings" "testing" - "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -1365,7 +1364,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) r.EqualValues(blk.Timestamp().UTC(), bt.CreateTime) r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) - r.EqualValues(time.Unix(0, 0).UTC(), bt.UnstakeStartTime) + r.True(bt.UnstakeStartTime.IsZero()) r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) t.Run("unlock", func(t *testing.T) { From 883fc9635a199b33b55ae37ea7c620219e7b8633 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 4 May 2023 12:11:06 +0800 Subject: [PATCH 26/51] fix bugs --- blockindex/liquidstaking_cache.go | 23 ++++++++++++----------- blockindex/liquidstaking_indexer.go | 9 +++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index a14f6c1aaa..09536b14ca 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -149,18 +149,19 @@ func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { if !ok { return votes } - for k, v := range m { - if v { - bi, ok := s.idBucketMap[k] - if !ok { - continue - } - if !bi.UnstakedAt.IsZero() { - continue - } - bt := s.mustGetBucketType(bi.TypeIndex) - votes.Add(votes, bt.Amount) + for id, existed := range m { + if !existed { + continue + } + bi, ok := s.idBucketMap[id] + if !ok { + continue + } + if !bi.UnstakedAt.IsZero() { + continue } + bt := s.mustGetBucketType(bi.TypeIndex) + votes.Add(votes, bt.Amount) } return votes } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index d0c3861206..156a3af72d 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -14,6 +14,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/hash" + "github.com/pkg/errors" + "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" @@ -21,7 +23,6 @@ import ( "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/pkg/errors" ) const ( @@ -443,12 +444,12 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { // PutBlock puts a block into indexer func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { actionMap := make(map[hash.Hash256]*action.SealedEnvelope) - for _, act := range blk.Actions { - h, err := act.Hash() + for i := range blk.Actions { + h, err := blk.Actions[i].Hash() if err != nil { return err } - actionMap[h] = &act + actionMap[h] = &blk.Actions[i] } s.dirtyCache.putHeight(blk.Height()) From 65dece3d037bb7324345b4022fccb98a846a3806 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 4 May 2023 23:46:08 +0800 Subject: [PATCH 27/51] refactor cache --- blockindex/liquidstaking_bucket.go | 5 +- blockindex/liquidstaking_cache.go | 48 ------ blockindex/liquidstaking_dirty.go | 150 ++++++++++++++++++ blockindex/liquidstaking_indexer.go | 235 ++++++++++------------------ e2etest/liquid_staking_test.go | 15 +- 5 files changed, 245 insertions(+), 208 deletions(-) create mode 100644 blockindex/liquidstaking_dirty.go diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index 6a1b1223e5..47e3493fee 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -10,11 +10,12 @@ import ( "time" "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-core/blockindex/indexpb" - "github.com/iotexproject/iotex-core/pkg/util/byteutil" "github.com/pkg/errors" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/iotexproject/iotex-core/blockindex/indexpb" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) type ( diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 09536b14ca..b335504203 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -8,9 +8,6 @@ package blockindex import ( "math/big" "time" - - "github.com/iotexproject/iotex-core/db/batch" - "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) type ( @@ -32,39 +29,6 @@ func newLiquidStakingCache() *liquidStakingCache { } } -func (s *liquidStakingCache) writeBatch(b batch.KVStoreBatch) error { - for i := 0; i < b.Size(); i++ { - write, err := b.Entry(i) - if err != nil { - return err - } - switch write.Namespace() { - case _liquidStakingBucketInfoNS: - if write.WriteType() == batch.Put { - var bi BucketInfo - if err = bi.deserialize(write.Value()); err != nil { - return err - } - id := byteutil.BytesToUint64BigEndian(write.Key()) - s.putBucketInfo(id, &bi) - } else if write.WriteType() == batch.Delete { - id := byteutil.BytesToUint64BigEndian(write.Key()) - s.deleteBucketInfo(id) - } - case _liquidStakingBucketTypeNS: - if write.WriteType() == batch.Put { - var bt BucketType - if err = bt.deserialize(write.Value()); err != nil { - return err - } - id := byteutil.BytesToUint64BigEndian(write.Key()) - s.putBucketType(id, &bt) - } - } - } - return nil -} - func (s *liquidStakingCache) putHeight(h uint64) { s.height = h } @@ -104,18 +68,6 @@ func (s *liquidStakingCache) deleteBucketInfo(id uint64) { delete(s.candidateBucketMap[bi.Delegate], id) } -func (s *liquidStakingCache) markDeleteBucketInfo(id uint64) { - bi, ok := s.idBucketMap[id] - if !ok { - return - } - s.idBucketMap[id] = nil - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - return - } - s.candidateBucketMap[bi.Delegate][id] = false -} - func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { m, ok := s.propertyBucketTypeMap[amount.Int64()] if !ok { diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go new file mode 100644 index 0000000000..78e5b4871e --- /dev/null +++ b/blockindex/liquidstaking_dirty.go @@ -0,0 +1,150 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "math/big" + "time" + + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/db/batch" + "github.com/iotexproject/iotex-core/pkg/util/byteutil" +) + +type ( + liquidStakingDelta struct { + *liquidStakingCache + updatedBucketType map[uint64]*BucketType + updatedBucketInfo map[uint64]*BucketInfo + deletedBucketInfo map[uint64]bool + } + + liquidStakingDirty struct { + kvstore db.KVStore + clean *liquidStakingCache + delta *liquidStakingDelta + batch batch.KVStoreBatch + tokenOwner map[uint64]string + } +) + +func newLiquidStakingDelta() *liquidStakingDelta { + return &liquidStakingDelta{ + liquidStakingCache: newLiquidStakingCache(), + updatedBucketType: make(map[uint64]*BucketType), + updatedBucketInfo: make(map[uint64]*BucketInfo), + deletedBucketInfo: make(map[uint64]bool), + } +} + +func (s *liquidStakingDelta) putBucketType(id uint64, bt *BucketType) { + s.liquidStakingCache.putBucketType(id, bt) + s.updatedBucketType[id] = bt +} + +func (s *liquidStakingDelta) putBucketInfo(id uint64, bi *BucketInfo) { + s.liquidStakingCache.putBucketInfo(id, bi) + s.updatedBucketInfo[id] = bi + if s.deletedBucketInfo[id] { + delete(s.deletedBucketInfo, id) + } +} + +func (s *liquidStakingDelta) deleteBucketInfo(id uint64) { + s.liquidStakingCache.deleteBucketInfo(id) + s.deletedBucketInfo[id] = true + if _, ok := s.updatedBucketInfo[id]; ok { + delete(s.updatedBucketInfo, id) + } +} + +func newLiquidStakingDirty(kvstore db.KVStore, clean *liquidStakingCache) *liquidStakingDirty { + return &liquidStakingDirty{ + kvstore: kvstore, + clean: clean, + delta: newLiquidStakingDelta(), + batch: batch.NewBatch(), + tokenOwner: make(map[uint64]string), + } +} + +func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { + for id, bt := range delta.updatedBucketType { + s.putBucketType(id, bt) + } + for id, bi := range delta.updatedBucketInfo { + s.putBucketInfo(id, bi) + } + for id := range delta.deletedBucketInfo { + s.deleteBucketInfo(id) + } + s.putHeight(delta.getHeight()) + return nil +} + +func (s *liquidStakingDirty) putHeight(h uint64) { + s.batch.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") + s.delta.putHeight(h) +} + +func (s *liquidStakingDirty) putBucketType(id uint64, bt *BucketType) { + s.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") + s.delta.putBucketType(id, bt) +} + +func (s *liquidStakingDirty) putBucketInfo(id uint64, bi *BucketInfo) { + s.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") + s.delta.putBucketInfo(id, bi) +} + +func (s *liquidStakingDirty) burnBucket(id uint64) { + s.batch.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") + s.delta.deleteBucketInfo(id) +} + +func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + id, ok := s.delta.getBucketTypeIndex(amount, duration) + if ok { + return id, true + } + id, ok = s.clean.getBucketTypeIndex(amount, duration) + return id, ok +} + +func (s *liquidStakingDirty) getBucketTypeCount() uint64 { + base := len(s.clean.idBucketTypeMap) + add := 0 + for k, dbt := range s.delta.idBucketTypeMap { + _, ok := s.clean.idBucketTypeMap[k] + if dbt != nil && !ok { + add++ + } else if dbt == nil && ok { + add-- + } + } + return uint64(base + add) +} + +func (s *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := s.delta.getBucketType(id) + if ok { + return bt, true + } + bt, ok = s.clean.getBucketType(id) + return bt, ok +} + +func (s *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { + if s.delta.deletedBucketInfo[id] { + return nil, false + } + bi, ok := s.delta.getBucketInfo(id) + if ok { + return bi, true + } + bi, ok = s.clean.getBucketInfo(id) + return bi, ok +} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 156a3af72d..33f4d10bca 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -14,15 +14,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/blockchain/block" "github.com/iotexproject/iotex-core/blockchain/blockdao" "github.com/iotexproject/iotex-core/db" - "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" - "github.com/iotexproject/iotex-proto/golang/iotextypes" ) const ( @@ -385,12 +384,8 @@ type ( } liquidStakingIndexer struct { - dirty batch.CachedBatch // batch for dirty data - kvstore db.KVStore // persistent storage - dirtyCache *liquidStakingCache // in-memory index for dirty data - cleanCache *liquidStakingCache // in-memory index for clean data - - tokenOwner map[uint64]string // token id -> owner + kvstore db.KVStore // persistent storage + cache *liquidStakingCache // in-memory index for clean data blockInterval time.Duration } ) @@ -417,11 +412,8 @@ func init() { func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) LiquidStakingIndexer { return &liquidStakingIndexer{ blockInterval: blockInterval, - dirty: batch.NewCachedBatch(), - dirtyCache: newLiquidStakingCache(), kvstore: kvStore, - cleanCache: newLiquidStakingCache(), - tokenOwner: make(map[uint64]string), + cache: newLiquidStakingCache(), } } @@ -443,6 +435,10 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { // PutBlock puts a block into indexer func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { + // new dirty cache + dirty := newLiquidStakingDirty(s.kvstore, s.cache) + dirty.putHeight(blk.Height()) + actionMap := make(map[hash.Hash256]*action.SealedEnvelope) for i := range blk.Actions { h, err := blk.Actions[i].Hash() @@ -451,8 +447,6 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } actionMap[h] = &blk.Actions[i] } - - s.dirtyCache.putHeight(blk.Height()) for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue @@ -465,12 +459,14 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e if log.Address != LiquidStakingContractAddress { continue } - if err := s.handleEvent(ctx, blk, act, log); err != nil { + if err := s.handleEvent(ctx, dirty, blk, act, log); err != nil { return err } } } - return s.commit() + + // commit dirty cache + return s.commit(dirty) } // DeleteTipBlock deletes the tip block from indexer @@ -480,19 +476,19 @@ func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) err // Height returns the tip block height func (s *liquidStakingIndexer) Height() (uint64, error) { - return s.cleanCache.getHeight(), nil + return s.cache.getHeight(), nil } // CandidateVotes returns the candidate votes func (s *liquidStakingIndexer) CandidateVotes(candidate string) *big.Int { - return s.cleanCache.getCandidateVotes(candidate) + return s.cache.getCandidateVotes(candidate) } // Buckets returns the buckets func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { vbs := []*Bucket{} - for id, bi := range s.cleanCache.idBucketMap { - bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) + for id, bi := range s.cache.idBucketMap { + bt := s.cache.mustGetBucketType(bi.TypeIndex) vb, err := convertToVoteBucket(id, bi, bt) if err != nil { return nil, err @@ -504,11 +500,11 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { // Bucket returns the bucket func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { - bi, ok := s.cleanCache.idBucketMap[id] + bi, ok := s.cache.idBucketMap[id] if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) } - bt := s.cleanCache.mustGetBucketType(bi.TypeIndex) + bt := s.cache.mustGetBucketType(bi.TypeIndex) vb, err := convertToVoteBucket(id, bi, bt) if err != nil { return nil, err @@ -516,7 +512,7 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { return vb, nil } -func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { +func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) if err != nil { @@ -533,35 +529,35 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, blk *block.Block timestamp := blk.Timestamp() switch abiEvent.Name { case "BucketTypeActivated": - return s.handleBucketTypeActivatedEvent(event, timestamp) + return s.handleBucketTypeActivatedEvent(dirty, event, timestamp) case "BucketTypeDeactivated": - return s.handleBucketTypeDeactivatedEvent(event) + return s.handleBucketTypeDeactivatedEvent(dirty, event) case "Staked": - return s.handleStakedEvent(event, timestamp) + return s.handleStakedEvent(dirty, event, timestamp) case "Locked": - return s.handleLockedEvent(event) + return s.handleLockedEvent(dirty, event) case "Unlocked": - return s.handleUnlockedEvent(event, timestamp) + return s.handleUnlockedEvent(dirty, event, timestamp) case "Unstaked": - return s.handleUnstakedEvent(event, timestamp) + return s.handleUnstakedEvent(dirty, event, timestamp) case "Merged": - return s.handleMergedEvent(event) + return s.handleMergedEvent(dirty, event) case "DurationExtended": - return s.handleDurationExtendedEvent(event) + return s.handleDurationExtendedEvent(dirty, event) case "AmountIncreased": - return s.handleAmountIncreasedEvent(event) + return s.handleAmountIncreasedEvent(dirty, event) case "DelegateChanged": - return s.handleDelegateChangedEvent(event) + return s.handleDelegateChangedEvent(dirty, event) case "Withdrawal": - return s.handleWithdrawalEvent(event) + return s.handleWithdrawalEvent(dirty, event) case "Transfer": - return s.handleTransferEvent(event) + return s.handleTransferEvent(dirty, event) default: return nil } } -func (s *liquidStakingIndexer) handleTransferEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleTransferEvent(dirty *liquidStakingDirty, event eventParam) error { to, err := event.indexedFieldAddress("to") if err != nil { return err @@ -571,11 +567,11 @@ func (s *liquidStakingIndexer) handleTransferEvent(event eventParam) error { return err } - s.tokenOwner[tokenID.Uint64()] = to.String() + dirty.tokenOwner[tokenID.Uint64()] = to.String() return nil } -func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, timeStamp time.Time) error { +func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStakingDirty, event eventParam, timeStamp time.Time) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -590,15 +586,15 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(event eventParam, Duration: s.blockHeightToDuration(durationParam.Uint64()), ActivatedAt: timeStamp, } - id, ok := s.getBucketTypeIndex(amountParam, bt.Duration) + id, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) if !ok { - id = s.getBucketTypeCount() + id = dirty.getBucketTypeCount() } - s.putBucketType(id, &bt) + dirty.putBucketType(id, &bt) return nil } -func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidStakingDirty, event eventParam) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -608,20 +604,20 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(event eventParam return err } - id, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + id, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - bt, ok := s.getBucketType(id) + bt, ok := dirty.getBucketType(id) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } bt.ActivatedAt = time.Time{} - s.putBucketType(id, bt) + dirty.putBucketType(id, bt) return nil } -func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -639,7 +635,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp tim return err } - btIdx, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } @@ -647,14 +643,14 @@ func (s *liquidStakingIndexer) handleStakedEvent(event eventParam, timestamp tim bucket := BucketInfo{ TypeIndex: btIdx, Delegate: delegateParam, - Owner: s.tokenOwner[tokenIDParam.Uint64()], + Owner: dirty.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } - s.putBucketInfo(tokenIDParam.Uint64(), &bucket) + dirty.putBucketInfo(tokenIDParam.Uint64(), &bucket) return nil } -func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleLockedEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -664,55 +660,55 @@ func (s *liquidStakingIndexer) handleLockedEvent(event eventParam) error { return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.getBucketType(b.TypeIndex) + bt, ok := dirty.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) } b.TypeIndex = newBtIdx b.UnlockedAt = time.Time{} - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleUnlockedEvent(event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnlockedAt = timestamp - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleUnstakedEvent(event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnstakedAt = timestamp - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDsParam, err := event.fieldUint256Slice("tokenIds") if err != nil { return err @@ -727,24 +723,24 @@ func (s *liquidStakingIndexer) handleMergedEvent(event eventParam) error { } // merge to the first bucket - btIdx, ok := s.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - b, ok := s.getBucketInfo(tokenIDsParam[0].Uint64()) + b, ok := dirty.getBucketInfo(tokenIDsParam[0].Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx b.UnlockedAt = time.Time{} for i := 1; i < len(tokenIDsParam); i++ { - s.burnBucket(tokenIDsParam[i].Uint64()) + dirty.burnBucket(tokenIDsParam[i].Uint64()) } - s.putBucketInfo(tokenIDsParam[0].Uint64(), b) + dirty.putBucketInfo(tokenIDsParam[0].Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleDurationExtendedEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -754,24 +750,24 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(event eventParam) err return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.getBucketType(b.TypeIndex) + bt, ok := dirty.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } b.TypeIndex = newBtIdx - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleAmountIncreasedEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -781,24 +777,24 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(event eventParam) erro return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - bt, ok := s.getBucketType(b.TypeIndex) + bt, ok := dirty.getBucketType(b.TypeIndex) if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := s.getBucketTypeIndex(amountParam, bt.Duration) + newBtIdx, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) } b.TypeIndex = newBtIdx - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -808,26 +804,27 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(event eventParam) erro return err } - b, ok := s.getBucketInfo(tokenIDParam.Uint64()) + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.Delegate = string(delegateParam[:]) - s.putBucketInfo(tokenIDParam.Uint64(), b) + dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } -func (s *liquidStakingIndexer) handleWithdrawalEvent(event eventParam) error { +func (s *liquidStakingIndexer) handleWithdrawalEvent(dirty *liquidStakingDirty, event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err } - s.burnBucket(tokenIDParam.Uint64()) + dirty.burnBucket(tokenIDParam.Uint64()) return nil } func (s *liquidStakingIndexer) loadCache() error { + delta := newLiquidStakingDelta() // load height var height uint64 h, err := s.kvstore.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) @@ -840,7 +837,7 @@ func (s *liquidStakingIndexer) loadCache() error { height = byteutil.BytesToUint64BigEndian(h) } - s.cleanCache.putHeight(height) + delta.putHeight(height) // load bucket info ks, vs, err := s.kvstore.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) @@ -854,7 +851,7 @@ func (s *liquidStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - s.cleanCache.putBucketInfo(byteutil.BytesToUint64BigEndian(ks[i]), &b) + delta.putBucketInfo(byteutil.BytesToUint64BigEndian(ks[i]), &b) } // load bucket type @@ -869,82 +866,18 @@ func (s *liquidStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - s.cleanCache.putBucketType(byteutil.BytesToUint64BigEndian(ks[i]), &b) - } - return nil -} - -func (s *liquidStakingIndexer) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { - id, ok := s.dirtyCache.getBucketTypeIndex(amount, duration) - if ok { - return id, true - } - id, ok = s.cleanCache.getBucketTypeIndex(amount, duration) - return id, ok -} - -func (s *liquidStakingIndexer) getBucketTypeCount() uint64 { - base := len(s.cleanCache.idBucketTypeMap) - add := 0 - for k, dbt := range s.dirtyCache.idBucketTypeMap { - _, ok := s.cleanCache.idBucketTypeMap[k] - if dbt != nil && !ok { - add++ - } else if dbt == nil && ok { - add-- - } + delta.putBucketType(byteutil.BytesToUint64BigEndian(ks[i]), &b) } - return uint64(base + add) -} - -func (s *liquidStakingIndexer) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.dirtyCache.getBucketType(id) - if ok { - return bt, true - } - bt, ok = s.cleanCache.getBucketType(id) - return bt, ok -} - -func (s *liquidStakingIndexer) putHeight(h uint64) { - s.dirty.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") - s.dirtyCache.putHeight(h) -} - -func (s *liquidStakingIndexer) putBucketType(id uint64, bt *BucketType) { - s.dirty.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") - s.dirtyCache.putBucketType(id, bt) -} - -func (s *liquidStakingIndexer) putBucketInfo(id uint64, bi *BucketInfo) { - s.dirty.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") - s.dirtyCache.putBucketInfo(id, bi) -} - -func (s *liquidStakingIndexer) getBucketInfo(id uint64) (*BucketInfo, bool) { - bi, ok := s.dirtyCache.getBucketInfo(id) - if ok { - return bi, bi != nil - } - bi, ok = s.cleanCache.getBucketInfo(id) - return bi, ok -} - -func (s *liquidStakingIndexer) burnBucket(id uint64) { - s.dirty.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") - s.dirtyCache.markDeleteBucketInfo(id) + return s.cache.merge(delta) } -func (s *liquidStakingIndexer) commit() error { - if err := s.cleanCache.writeBatch(s.dirty); err != nil { +func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { + if err := s.kvstore.WriteBatch(dirty.batch); err != nil { return err } - if err := s.kvstore.WriteBatch(s.dirty); err != nil { + if err := s.cache.merge(dirty.delta); err != nil { return err } - s.dirty.Lock() - s.dirty.ClearAndUnlock() - s.dirtyCache = newLiquidStakingCache() return nil } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 66b937b33d..223db70eee 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -11,6 +11,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" + "github.com/iotexproject/iotex-core/action" "github.com/iotexproject/iotex-core/action/protocol" "github.com/iotexproject/iotex-core/action/protocol/account" @@ -29,9 +33,6 @@ import ( "github.com/iotexproject/iotex-core/state/factory" "github.com/iotexproject/iotex-core/test/identityset" "github.com/iotexproject/iotex-core/testutil" - "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) const ( @@ -1362,8 +1363,8 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(identityset.PrivateKey(1).PublicKey().Address().String(), bt.Owner.String()) r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) - r.EqualValues(blk.Timestamp().UTC(), bt.CreateTime) - r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) + r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) + r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.True(bt.UnstakeStartTime.IsZero()) r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) @@ -1384,7 +1385,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Timestamp().UTC(), bt.StakeStartTime) + r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) t.Run("unstake", func(t *testing.T) { @@ -1405,7 +1406,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Timestamp().UTC(), bt.UnstakeStartTime) + r.EqualValues(blk.Timestamp().UTC().Unix(), bt.UnstakeStartTime.Unix()) r.EqualValues(0, indexer.CandidateVotes("delegate2").Int64()) t.Run("withdraw", func(t *testing.T) { From 769c2f80e518e5b7d4b89f8e1591ef8b93cad22d Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 5 May 2023 00:35:18 +0800 Subject: [PATCH 28/51] fix test --- blockindex/liquidstaking_indexer.go | 2 +- e2etest/liquid_staking_test.go | 40 ++++++++++++++++------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 33f4d10bca..48d4564fd8 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -27,7 +27,7 @@ import ( const ( // LiquidStakingContractAddress is the address of liquid staking contract // TODO (iip-13): replace with the real liquid staking contract address - LiquidStakingContractAddress = "io1dkqh5mu9djfas3xyrmzdv9frsmmytel4mp7a64" + LiquidStakingContractAddress = "io19ys8f4uhwms6lq6ulexr5fwht9gsjes8mvuugd" // LiquidStakingContractABI is the ABI of liquid staking contract LiquidStakingContractABI = `[ { diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 223db70eee..49a13eba6e 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1269,16 +1269,19 @@ const ( "type": "function" } ]` + + _adminID = 22 ) func TestLiquidStaking(t *testing.T) { r := require.New(t) // prepare blockchain + adminID := _adminID ctx := context.Background() cfg := config.Default - cfg.Chain.ProducerPrivKey = identityset.PrivateKey(1).HexString() + cfg.Chain.ProducerPrivKey = identityset.PrivateKey(adminID).HexString() cfg.Chain.EnableTrielessStateDB = false - cfg.Genesis.InitBalanceMap[identityset.Address(1).String()] = "1000000000000000000000000000" + cfg.Genesis.InitBalanceMap[identityset.Address(adminID).String()] = "1000000000000000000000000000" bc, sf, dao, ap, indexer := prepareliquidStakingBlockchain(ctx, cfg, r) defer func() { @@ -1294,9 +1297,10 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 20000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } contractAddresses := deployContracts(bc, sf, dao, ap, ¶m, r) + r.Equal(deployAddr, contractAddresses) lsdABI, err := abi.JSON(strings.NewReader(_liquidStakingContractABI)) r.NoError(err) @@ -1320,7 +1324,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } params = append(params, ¶m) } @@ -1345,7 +1349,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(10), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, blk := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1360,7 +1364,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(1, bt.Index) r.True(bt.AutoStake) r.Equal("delegate2", bt.Candidate) - r.EqualValues(identityset.PrivateKey(1).PublicKey().Address().String(), bt.Owner.String()) + r.EqualValues(identityset.PrivateKey(adminID).PublicKey().Address().String(), bt.Owner.String()) r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) @@ -1377,7 +1381,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, blk = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1398,7 +1402,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, blk = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1414,7 +1418,7 @@ func TestLiquidStaking(t *testing.T) { jumpBlocks(bc, 10, r) tokenID := bt.Index - addr := common.BytesToAddress(identityset.PrivateKey(1).PublicKey().Bytes()) + addr := common.BytesToAddress(identityset.PrivateKey(adminID).PublicKey().Bytes()) data, err := lsdABI.Pack("withdraw", big.NewInt(int64(tokenID)), addr) r.NoError(err) param = callParam{ @@ -1423,7 +1427,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1448,7 +1452,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1463,7 +1467,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1488,7 +1492,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(10), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } params = append(params, ¶m) } @@ -1517,7 +1521,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1549,7 +1553,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1571,7 +1575,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(90), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1597,7 +1601,7 @@ func TestLiquidStaking(t *testing.T) { amount: big.NewInt(0), gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(adminID), } receipts, _ = writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) @@ -1834,7 +1838,7 @@ func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blo amount: amount, gasLimit: 1000000, gasPrice: big.NewInt(0), - sk: identityset.PrivateKey(1), + sk: identityset.PrivateKey(_adminID), } receipts, _ := writeContract(bc, sf, dao, ap, []*callParam{¶m}, r) r.Len(receipts, 1) From 81720039f080eca2050d8e00633e0f70a95fd310 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 8 May 2023 21:25:10 +0800 Subject: [PATCH 29/51] add comments --- blockindex/liquidstaking_dirty.go | 27 +++++++++++++++------------ blockindex/liquidstaking_indexer.go | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 78e5b4871e..1beecbcee7 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -9,26 +9,30 @@ import ( "math/big" "time" - "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) type ( + // liquidStakingDirty is the dirty data of liquid staking + // main functions: + // 1. update bucket + // 2. get up-to-date bucket + // 3. store delta to merge to clean cache + liquidStakingDirty struct { + clean *liquidStakingCache // clean cache to get buckets of last block + delta *liquidStakingDelta // delta for cache to store buckets of current block + batch batch.KVStoreBatch // batch for db to store buckets of current block + tokenOwner map[uint64]string + } + liquidStakingDelta struct { - *liquidStakingCache + *liquidStakingCache // easy to query buckets + updatedBucketType map[uint64]*BucketType updatedBucketInfo map[uint64]*BucketInfo deletedBucketInfo map[uint64]bool } - - liquidStakingDirty struct { - kvstore db.KVStore - clean *liquidStakingCache - delta *liquidStakingDelta - batch batch.KVStoreBatch - tokenOwner map[uint64]string - } ) func newLiquidStakingDelta() *liquidStakingDelta { @@ -61,9 +65,8 @@ func (s *liquidStakingDelta) deleteBucketInfo(id uint64) { } } -func newLiquidStakingDirty(kvstore db.KVStore, clean *liquidStakingCache) *liquidStakingDirty { +func newLiquidStakingDirty(clean *liquidStakingCache) *liquidStakingDirty { return &liquidStakingDirty{ - kvstore: kvstore, clean: clean, delta: newLiquidStakingDelta(), batch: batch.NewBatch(), diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 48d4564fd8..928df019d1 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -382,6 +382,16 @@ type ( Buckets() ([]*Bucket, error) Bucket(id uint64) (*Bucket, error) } + // liquidStakingIndexer is the implementation of LiquidStakingIndexer + // Main functions: + // 1. handle liquid staking contract events when new block comes to generate index data + // 2. provide query interface for liquid staking index data + // Generate index data flow: + // block comes -> new dirty cache -> handle contract events -> update dirty cache -> merge dirty to clean cache + // Main Object: + // kvstore: persistent storage, used to initialize index cache at startup + // cache: in-memory index for clean data, used to query index data + // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. liquidStakingIndexer struct { kvstore db.KVStore // persistent storage @@ -436,9 +446,9 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { // PutBlock puts a block into indexer func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { // new dirty cache - dirty := newLiquidStakingDirty(s.kvstore, s.cache) + dirty := newLiquidStakingDirty(s.cache) dirty.putHeight(blk.Height()) - + // make action map actionMap := make(map[hash.Hash256]*action.SealedEnvelope) for i := range blk.Actions { h, err := blk.Actions[i].Hash() @@ -447,6 +457,8 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } actionMap[h] = &blk.Actions[i] } + + // handle events of block for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue From 81a7706fb73909306f2a191821c9232e1aa4f8d2 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 9 May 2023 15:19:58 +0800 Subject: [PATCH 30/51] use staking.VoteBucket --- blockindex/liquidstaking_bucket.go | 37 ++------------------ blockindex/liquidstaking_indexer.go | 53 ++++++++++++++++++++++------- e2etest/liquid_staking_test.go | 42 ++++++++++++++++++----- 3 files changed, 76 insertions(+), 56 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index 47e3493fee..45b05658ec 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -9,11 +9,11 @@ import ( "math/big" "time" - "github.com/iotexproject/iotex-address/address" "github.com/pkg/errors" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockindex/indexpb" "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) @@ -37,17 +37,7 @@ type ( } // Bucket is the bucket information including bucket type and bucket info - Bucket struct { - Index uint64 - Candidate string - Owner address.Address - StakedAmount *big.Int - StakedDuration time.Duration - CreateTime time.Time - StakeStartTime time.Time - UnstakeStartTime time.Time - AutoStake bool - } + Bucket = staking.VoteBucket ) func (bt *BucketType) toProto() *indexpb.BucketType { @@ -127,26 +117,3 @@ func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { bi.Owner = p.Owner return nil } - -func convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { - var err error - vb := Bucket{ - Index: token, - StakedAmount: bt.Amount, - StakedDuration: bt.Duration, - CreateTime: bi.CreatedAt, - StakeStartTime: bi.CreatedAt, - UnstakeStartTime: bi.UnstakedAt, - AutoStake: bi.UnlockedAt.IsZero(), - Candidate: bi.Delegate, - } - - vb.Owner, err = address.FromHex(bi.Owner) - if err != nil { - return nil, err - } - if !bi.UnlockedAt.IsZero() { - vb.StakeStartTime = bi.UnlockedAt - } - return &vb, nil -} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 928df019d1..8053a4b8fd 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" @@ -382,6 +383,7 @@ type ( Buckets() ([]*Bucket, error) Bucket(id uint64) (*Bucket, error) } + // liquidStakingIndexer is the implementation of LiquidStakingIndexer // Main functions: // 1. handle liquid staking contract events when new block comes to generate index data @@ -392,12 +394,13 @@ type ( // kvstore: persistent storage, used to initialize index cache at startup // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. - liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *liquidStakingCache // in-memory index for clean data - blockInterval time.Duration + kvstore db.KVStore // persistent storage + cache *liquidStakingCache // in-memory index for clean data + blockInterval time.Duration + candNameToOwnerFunc candNameToOwnerFunc } + candNameToOwnerFunc func(name string) (address.Address, error) ) var ( @@ -419,11 +422,12 @@ func init() { } // NewLiquidStakingIndexer creates a new liquid staking indexer -func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) LiquidStakingIndexer { +func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration, candNameToOwnerFunc candNameToOwnerFunc) LiquidStakingIndexer { return &liquidStakingIndexer{ - blockInterval: blockInterval, - kvstore: kvStore, - cache: newLiquidStakingCache(), + blockInterval: blockInterval, + kvstore: kvStore, + cache: newLiquidStakingCache(), + candNameToOwnerFunc: candNameToOwnerFunc, } } @@ -492,8 +496,8 @@ func (s *liquidStakingIndexer) Height() (uint64, error) { } // CandidateVotes returns the candidate votes -func (s *liquidStakingIndexer) CandidateVotes(candidate string) *big.Int { - return s.cache.getCandidateVotes(candidate) +func (s *liquidStakingIndexer) CandidateVotes(ownerAddr string) *big.Int { + return s.cache.getCandidateVotes(ownerAddr) } // Buckets returns the buckets @@ -501,7 +505,7 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { vbs := []*Bucket{} for id, bi := range s.cache.idBucketMap { bt := s.cache.mustGetBucketType(bi.TypeIndex) - vb, err := convertToVoteBucket(id, bi, bt) + vb, err := s.convertToVoteBucket(id, bi, bt) if err != nil { return nil, err } @@ -517,7 +521,7 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) } bt := s.cache.mustGetBucketType(bi.TypeIndex) - vb, err := convertToVoteBucket(id, bi, bt) + vb, err := s.convertToVoteBucket(id, bi, bt) if err != nil { return nil, err } @@ -896,3 +900,28 @@ func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { return time.Duration(height) * s.blockInterval } + +func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { + var err error + vb := Bucket{ + Index: token, + StakedAmount: bt.Amount, + StakedDuration: bt.Duration, + CreateTime: bi.CreatedAt, + StakeStartTime: bi.CreatedAt, + UnstakeStartTime: bi.UnstakedAt, + AutoStake: bi.UnlockedAt.IsZero(), + } + vb.Candidate, err = s.candNameToOwnerFunc(bi.Delegate) + if err != nil { + return nil, err + } + vb.Owner, err = address.FromHex(bi.Owner) + if err != nil { + return nil, err + } + if !bi.UnlockedAt.IsZero() { + vb.StakeStartTime = bi.UnlockedAt + } + return &vb, nil +} diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 49a13eba6e..e5c9aad49a 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -11,7 +11,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" + "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/pkg/errors" "github.com/stretchr/testify/require" "golang.org/x/exp/slices" @@ -1273,6 +1275,18 @@ const ( _adminID = 22 ) +var ( + _delegates = []string{ + "delegate0", + "delegate1", + "delegate2", + "delegate3", + "delegate4", + "delegate5", + "delegate6", + } +) + func TestLiquidStaking(t *testing.T) { r := require.New(t) // prepare blockchain @@ -1339,8 +1353,9 @@ func TestLiquidStaking(t *testing.T) { } t.Run("stake", func(t *testing.T) { + delegateIdx := 2 delegate := [12]byte{} - copy(delegate[:], []byte("delegate2")) + copy(delegate[:], []byte(_delegates[delegateIdx])) data, err := lsdABI.Pack("stake", big.NewInt(10), delegate) r.NoError(err) param := callParam{ @@ -1363,14 +1378,14 @@ func TestLiquidStaking(t *testing.T) { tokenID := bt.Index r.EqualValues(1, bt.Index) r.True(bt.AutoStake) - r.Equal("delegate2", bt.Candidate) + r.Equal(identityset.Address(delegateIdx).String(), bt.Candidate.String()) r.EqualValues(identityset.PrivateKey(adminID).PublicKey().Address().String(), bt.Owner.String()) r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.True(bt.UnstakeStartTime.IsZero()) - r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) + r.EqualValues(10, indexer.CandidateVotes(_delegates[delegateIdx]).Int64()) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) @@ -1390,7 +1405,7 @@ func TestLiquidStaking(t *testing.T) { bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) - r.EqualValues(10, indexer.CandidateVotes("delegate2").Int64()) + r.EqualValues(10, indexer.CandidateVotes(_delegates[delegateIdx]).Int64()) t.Run("unstake", func(t *testing.T) { jumpBlocks(bc, 10, r) @@ -1587,12 +1602,14 @@ func TestLiquidStaking(t *testing.T) { }) t.Run("change delegate", func(t *testing.T) { - bt := simpleStake("delegate5", big.NewInt(10), big.NewInt(10)) + delegateIdx := 5 + bt := simpleStake(_delegates[delegateIdx], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index - r.EqualValues("delegate5", bt.Candidate) + r.EqualValues(identityset.Address(delegateIdx).String(), bt.Candidate.String()) + delegateIdx = 6 delegate := [12]byte{} - copy(delegate[:], []byte("delegate6")) + copy(delegate[:], []byte(_delegates[delegateIdx])) data, err := lsdABI.Pack("changeDelegate", big.NewInt(int64(tokenID)), delegate) r.NoError(err) param = callParam{ @@ -1609,7 +1626,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues("delegate6", bt.Candidate) + r.EqualValues(identityset.Address(delegateIdx).String(), bt.Candidate.String()) }) } @@ -1682,7 +1699,14 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r r.NoError(err) cc := cfg.DB cc.DbPath = testLiquidStakeIndexerPath - liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) + candNameToOwner := func(name string) (address.Address, error) { + idx := slices.Index(_delegates, name) + if idx == -1 { + return &address.AddrV1{}, errors.New("delegate not found") + } + return identityset.Address(idx), nil + } + liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval, candNameToOwner) // create BlockDAO dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) r.NotNil(dao) From 4611ad7642ccf9b7955f4467a1f5b6e3cc679a7e Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 9 May 2023 15:32:10 +0800 Subject: [PATCH 31/51] use candidate owner as identity instead of name --- blockindex/liquidstaking_bucket.go | 2 +- blockindex/liquidstaking_cache.go | 4 ++-- blockindex/liquidstaking_indexer.go | 17 ++++++++++++----- e2etest/liquid_staking_test.go | 6 +++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index 45b05658ec..d2067e2603 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -25,7 +25,7 @@ type ( CreatedAt time.Time UnlockedAt time.Time UnstakedAt time.Time - Delegate string + Delegate string // owner address of the delegate Owner string } diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index b335504203..8d045690e4 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -95,9 +95,9 @@ func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { return bi, ok } -func (s *liquidStakingCache) getCandidateVotes(name string) *big.Int { +func (s *liquidStakingCache) getCandidateVotes(ownerAddr string) *big.Int { votes := big.NewInt(0) - m, ok := s.candidateBucketMap[name] + m, ok := s.candidateBucketMap[ownerAddr] if !ok { return votes } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 8053a4b8fd..3dd334ba8d 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -379,7 +379,7 @@ type ( LiquidStakingIndexer interface { blockdao.BlockIndexer - CandidateVotes(candidate string) *big.Int + CandidateVotes(ownerAddr string) *big.Int Buckets() ([]*Bucket, error) Bucket(id uint64) (*Bucket, error) } @@ -655,10 +655,13 @@ func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, even if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - + delegateOwner, err := s.candNameToOwnerFunc(delegateParam) + if err != nil { + return errors.Wrapf(err, "get delegate owner from %v failed", delegateParam) + } bucket := BucketInfo{ TypeIndex: btIdx, - Delegate: delegateParam, + Delegate: delegateOwner.String(), Owner: dirty.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } @@ -824,7 +827,11 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDi if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - b.Delegate = string(delegateParam[:]) + delegateOwner, err := s.candNameToOwnerFunc(delegateParam) + if err != nil { + return errors.Wrapf(err, "get owner of candidate %s", delegateParam) + } + b.Delegate = delegateOwner.String() dirty.putBucketInfo(tokenIDParam.Uint64(), b) return nil } @@ -912,7 +919,7 @@ func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, UnstakeStartTime: bi.UnstakedAt, AutoStake: bi.UnlockedAt.IsZero(), } - vb.Candidate, err = s.candNameToOwnerFunc(bi.Delegate) + vb.Candidate, err = address.FromString(bi.Delegate) if err != nil { return nil, err } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index e5c9aad49a..6439e8c96d 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1385,7 +1385,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.True(bt.UnstakeStartTime.IsZero()) - r.EqualValues(10, indexer.CandidateVotes(_delegates[delegateIdx]).Int64()) + r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) @@ -1405,7 +1405,7 @@ func TestLiquidStaking(t *testing.T) { bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) - r.EqualValues(10, indexer.CandidateVotes(_delegates[delegateIdx]).Int64()) + r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) t.Run("unstake", func(t *testing.T) { jumpBlocks(bc, 10, r) @@ -1426,7 +1426,7 @@ func TestLiquidStaking(t *testing.T) { bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.UnstakeStartTime.Unix()) - r.EqualValues(0, indexer.CandidateVotes("delegate2").Int64()) + r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) t.Run("withdraw", func(t *testing.T) { // freeze blocks are changed to 10 in test From 72b736cea70fc32ec3cc8d08a3df02e3c673d78d Mon Sep 17 00:00:00 2001 From: envestcc Date: Sat, 13 May 2023 00:20:18 +0800 Subject: [PATCH 32/51] add BucketsByIndices & TotalBucketCount refactor delta --- blockindex/liquidstaking_cache.go | 17 +++ blockindex/liquidstaking_delta.go | 155 ++++++++++++++++++++++++++++ blockindex/liquidstaking_dirty.go | 96 ++++++++--------- blockindex/liquidstaking_indexer.go | 91 ++++++++++------ blockindex/util.go | 3 +- e2etest/liquid_staking_test.go | 4 + 6 files changed, 283 insertions(+), 83 deletions(-) create mode 100644 blockindex/liquidstaking_delta.go diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 8d045690e4..2c16977f67 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -17,6 +17,7 @@ type ( idBucketTypeMap map[uint64]*BucketType // map[token]BucketType propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index height uint64 + totalBucketCount uint64 // total number of buckets including burned buckets } ) @@ -95,6 +96,14 @@ func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { return bi, ok } +func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *BucketInfo { + bt, ok := s.idBucketMap[id] + if !ok { + panic("bucket info not found") + } + return bt +} + func (s *liquidStakingCache) getCandidateVotes(ownerAddr string) *big.Int { votes := big.NewInt(0) m, ok := s.candidateBucketMap[ownerAddr] @@ -117,3 +126,11 @@ func (s *liquidStakingCache) getCandidateVotes(ownerAddr string) *big.Int { } return votes } + +func (s *liquidStakingCache) putTotalBucketCount(count uint64) { + s.totalBucketCount = count +} + +func (s *liquidStakingCache) getTotalBucketCount() uint64 { + return s.totalBucketCount +} diff --git a/blockindex/liquidstaking_delta.go b/blockindex/liquidstaking_delta.go new file mode 100644 index 0000000000..3adf7b3851 --- /dev/null +++ b/blockindex/liquidstaking_delta.go @@ -0,0 +1,155 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import "github.com/pkg/errors" + +const ( + deltaStateAdded deltaState = iota + deltaStateRemoved + deltaStateModified + deltaStateReverted + + deltaActionAdd deltaAction = iota + deltaActionRemove + deltaActionModify +) + +type ( + deltaState int + deltaAction int + + liquidStakingDelta struct { + *liquidStakingCache // easy to query buckets + + bucketTypeDeltaState map[uint64]deltaState + bucketInfoDeltaState map[uint64]deltaState + } +) + +var ( + deltaStateTransferMap = map[deltaState]map[deltaAction]deltaState{ + deltaStateAdded: { + deltaActionRemove: deltaStateReverted, + deltaActionModify: deltaStateAdded, + }, + deltaStateRemoved: { + deltaActionAdd: deltaStateModified, + }, + deltaStateModified: { + deltaActionModify: deltaStateModified, + deltaActionRemove: deltaStateRemoved, + }, + deltaStateReverted: { + deltaActionAdd: deltaStateAdded, + }, + } +) + +func (s deltaState) transfer(act deltaAction) (deltaState, error) { + if _, ok := deltaStateTransferMap[s]; !ok { + return s, errors.New("invalid delta state") + } + if _, ok := deltaStateTransferMap[s][act]; !ok { + return s, errors.New("invalid delta action") + } + return deltaStateTransferMap[s][act], nil +} + +func newLiquidStakingDelta() *liquidStakingDelta { + return &liquidStakingDelta{ + liquidStakingCache: newLiquidStakingCache(), + bucketTypeDeltaState: make(map[uint64]deltaState), + bucketInfoDeltaState: make(map[uint64]deltaState), + } +} + +func (s *liquidStakingDelta) addBucketType(id uint64, bt *BucketType) error { + if _, ok := s.bucketTypeDeltaState[id]; !ok { + s.bucketTypeDeltaState[id] = deltaStateAdded + } else { + var err error + s.bucketTypeDeltaState[id], err = s.bucketTypeDeltaState[id].transfer(deltaActionAdd) + if err != nil { + return err + } + } + s.liquidStakingCache.putBucketType(id, bt) + return nil +} + +func (s *liquidStakingDelta) updateBucketType(id uint64, bt *BucketType) error { + if _, ok := s.bucketTypeDeltaState[id]; !ok { + s.bucketTypeDeltaState[id] = deltaStateModified + } else { + var err error + s.bucketTypeDeltaState[id], err = s.bucketTypeDeltaState[id].transfer(deltaActionModify) + if err != nil { + return err + } + } + s.liquidStakingCache.putBucketType(id, bt) + return nil +} + +func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *BucketInfo) error { + var err error + if _, ok := s.bucketInfoDeltaState[id]; !ok { + s.bucketInfoDeltaState[id] = deltaStateAdded + } else { + s.bucketInfoDeltaState[id], err = s.bucketInfoDeltaState[id].transfer(deltaActionAdd) + if err != nil { + return err + } + } + s.liquidStakingCache.putBucketInfo(id, bi) + return nil +} + +func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *BucketInfo) error { + if _, ok := s.bucketInfoDeltaState[id]; !ok { + s.bucketInfoDeltaState[id] = deltaStateModified + } else { + var err error + s.bucketInfoDeltaState[id], err = s.bucketInfoDeltaState[id].transfer(deltaActionModify) + if err != nil { + return err + } + } + s.liquidStakingCache.putBucketInfo(id, bi) + return nil +} + +func (s *liquidStakingDelta) deleteBucketInfo(id uint64) error { + if _, ok := s.bucketInfoDeltaState[id]; !ok { + s.bucketInfoDeltaState[id] = deltaStateRemoved + } else { + var err error + s.bucketInfoDeltaState[id], err = s.bucketInfoDeltaState[id].transfer(deltaActionRemove) + if err != nil { + return err + } + } + s.liquidStakingCache.deleteBucketInfo(id) + return nil +} + +func (s *liquidStakingDelta) addedBucketCnt() uint64 { + addedBucketCnt := uint64(0) + for _, state := range s.bucketInfoDeltaState { + if state == deltaStateAdded { + addedBucketCnt++ + } + } + return addedBucketCnt +} + +func (s *liquidStakingDelta) isBucketDeleted(id uint64) bool { + if _, ok := s.bucketInfoDeltaState[id]; ok { + return s.bucketInfoDeltaState[id] == deltaStateRemoved + } + return false +} diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 1beecbcee7..e78819e32e 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -7,6 +7,7 @@ package blockindex import ( "math/big" + "sync" "time" "github.com/iotexproject/iotex-core/db/batch" @@ -24,47 +25,10 @@ type ( delta *liquidStakingDelta // delta for cache to store buckets of current block batch batch.KVStoreBatch // batch for db to store buckets of current block tokenOwner map[uint64]string - } - - liquidStakingDelta struct { - *liquidStakingCache // easy to query buckets - - updatedBucketType map[uint64]*BucketType - updatedBucketInfo map[uint64]*BucketInfo - deletedBucketInfo map[uint64]bool + once sync.Once } ) -func newLiquidStakingDelta() *liquidStakingDelta { - return &liquidStakingDelta{ - liquidStakingCache: newLiquidStakingCache(), - updatedBucketType: make(map[uint64]*BucketType), - updatedBucketInfo: make(map[uint64]*BucketInfo), - deletedBucketInfo: make(map[uint64]bool), - } -} - -func (s *liquidStakingDelta) putBucketType(id uint64, bt *BucketType) { - s.liquidStakingCache.putBucketType(id, bt) - s.updatedBucketType[id] = bt -} - -func (s *liquidStakingDelta) putBucketInfo(id uint64, bi *BucketInfo) { - s.liquidStakingCache.putBucketInfo(id, bi) - s.updatedBucketInfo[id] = bi - if s.deletedBucketInfo[id] { - delete(s.deletedBucketInfo, id) - } -} - -func (s *liquidStakingDelta) deleteBucketInfo(id uint64) { - s.liquidStakingCache.deleteBucketInfo(id) - s.deletedBucketInfo[id] = true - if _, ok := s.updatedBucketInfo[id]; ok { - delete(s.updatedBucketInfo, id) - } -} - func newLiquidStakingDirty(clean *liquidStakingCache) *liquidStakingDirty { return &liquidStakingDirty{ clean: clean, @@ -75,37 +39,51 @@ func newLiquidStakingDirty(clean *liquidStakingCache) *liquidStakingDirty { } func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { - for id, bt := range delta.updatedBucketType { - s.putBucketType(id, bt) - } - for id, bi := range delta.updatedBucketInfo { - s.putBucketInfo(id, bi) + for id, state := range delta.bucketTypeDeltaState { + if state == deltaStateAdded || state == deltaStateModified { + s.putBucketType(id, delta.mustGetBucketType(id)) + } } - for id := range delta.deletedBucketInfo { - s.deleteBucketInfo(id) + for id, state := range delta.bucketInfoDeltaState { + if state == deltaStateAdded || state == deltaStateModified { + s.putBucketInfo(id, delta.mustGetBucketInfo(id)) + } else if state == deltaStateRemoved { + s.deleteBucketInfo(id) + } } s.putHeight(delta.getHeight()) + s.putTotalBucketCount(s.getTotalBucketCount() + delta.addedBucketCnt()) return nil } func (s *liquidStakingDirty) putHeight(h uint64) { - s.batch.Put(_liquidStakingHeightNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") + s.batch.Put(_liquidStakingNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") s.delta.putHeight(h) } -func (s *liquidStakingDirty) putBucketType(id uint64, bt *BucketType) { +func (s *liquidStakingDirty) addBucketType(id uint64, bt *BucketType) error { s.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") - s.delta.putBucketType(id, bt) + return s.delta.addBucketType(id, bt) } -func (s *liquidStakingDirty) putBucketInfo(id uint64, bi *BucketInfo) { +func (s *liquidStakingDirty) updateBucketType(id uint64, bt *BucketType) error { + s.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") + return s.delta.updateBucketType(id, bt) +} + +func (s *liquidStakingDirty) addBucketInfo(id uint64, bi *BucketInfo) error { s.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") - s.delta.putBucketInfo(id, bi) + return s.delta.addBucketInfo(id, bi) } -func (s *liquidStakingDirty) burnBucket(id uint64) { +func (s *liquidStakingDirty) updateBucketInfo(id uint64, bi *BucketInfo) error { + s.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") + return s.delta.updateBucketInfo(id, bi) +} + +func (s *liquidStakingDirty) burnBucket(id uint64) error { s.batch.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") - s.delta.deleteBucketInfo(id) + return s.delta.deleteBucketInfo(id) } func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { @@ -141,7 +119,7 @@ func (s *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { } func (s *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { - if s.delta.deletedBucketInfo[id] { + if s.delta.isBucketDeleted(id) { return nil, false } bi, ok := s.delta.getBucketInfo(id) @@ -151,3 +129,15 @@ func (s *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { bi, ok = s.clean.getBucketInfo(id) return bi, ok } + +func (s *liquidStakingDirty) finalizeBatch() batch.KVStoreBatch { + s.once.Do(func() { + total := s.clean.getTotalBucketCount() + s.delta.addedBucketCnt() + s.batch.Put(_liquidStakingNS, _liquidStakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(total), "failed to put total bucket count") + }) + return s.batch +} + +func (s *liquidStakingDirty) finalize() (batch.KVStoreBatch, *liquidStakingDelta) { + return s.finalizeBatch(), s.delta +} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 3dd334ba8d..2a219af156 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -371,7 +371,7 @@ const ( // bucket related namespace in db _liquidStakingBucketInfoNS = "lsbInfo" _liquidStakingBucketTypeNS = "lsbType" - _liquidStakingHeightNS = "lsHeight" + _liquidStakingNS = "lsns" ) type ( @@ -382,6 +382,8 @@ type ( CandidateVotes(ownerAddr string) *big.Int Buckets() ([]*Bucket, error) Bucket(id uint64) (*Bucket, error) + BucketsByIndices(indices []uint64) ([]*Bucket, error) + TotalBucketCount() uint64 } // liquidStakingIndexer is the implementation of LiquidStakingIndexer @@ -404,8 +406,9 @@ type ( ) var ( - _liquidStakingInterface abi.ABI - _liquidStakingHeightKey = []byte("lsHeight") + _liquidStakingInterface abi.ABI + _liquidStakingHeightKey = []byte("lsHeight") + _liquidStakingTotalBucketCountKey = []byte("lsTotalBucketCount") errBucketTypeNotExist = errors.New("bucket type does not exist") @@ -528,6 +531,28 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { return vb, nil } +// BucketsByIndices returns the buckets by indices +func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*Bucket, error) { + vbs := make([]*Bucket, 0, len(indices)) + for _, id := range indices { + bi, ok := s.cache.idBucketMap[id] + if !ok { + return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) + } + bt := s.cache.mustGetBucketType(bi.TypeIndex) + vb, err := s.convertToVoteBucket(id, bi, bt) + if err != nil { + return nil, err + } + vbs = append(vbs, vb) + } + return vbs, nil +} + +func (s *liquidStakingIndexer) TotalBucketCount() uint64 { + return s.cache.getTotalBucketCount() +} + func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) @@ -605,9 +630,12 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStaki id, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) if !ok { id = dirty.getBucketTypeCount() + err = dirty.addBucketType(id, &bt) + } else { + err = dirty.updateBucketType(id, &bt) } - dirty.putBucketType(id, &bt) - return nil + + return err } func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -629,8 +657,7 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidSta return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } bt.ActivatedAt = time.Time{} - dirty.putBucketType(id, bt) - return nil + return dirty.updateBucketType(id, bt) } func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { @@ -665,8 +692,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, even Owner: dirty.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } - dirty.putBucketInfo(tokenIDParam.Uint64(), &bucket) - return nil + return dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) } func (s *liquidStakingIndexer) handleLockedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -693,8 +719,7 @@ func (s *liquidStakingIndexer) handleLockedEvent(dirty *liquidStakingDirty, even } b.TypeIndex = newBtIdx b.UnlockedAt = time.Time{} - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { @@ -708,8 +733,7 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, ev return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnlockedAt = timestamp - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { @@ -723,8 +747,7 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, ev return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } b.UnstakedAt = timestamp - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -753,10 +776,11 @@ func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, even b.TypeIndex = btIdx b.UnlockedAt = time.Time{} for i := 1; i < len(tokenIDsParam); i++ { - dirty.burnBucket(tokenIDsParam[i].Uint64()) + if err = dirty.burnBucket(tokenIDsParam[i].Uint64()); err != nil { + return err + } } - dirty.putBucketInfo(tokenIDsParam[0].Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDsParam[0].Uint64(), b) } func (s *liquidStakingIndexer) handleDurationExtendedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -782,8 +806,7 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(dirty *liquidStakingD return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } b.TypeIndex = newBtIdx - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleAmountIncreasedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -809,8 +832,7 @@ func (s *liquidStakingIndexer) handleAmountIncreasedEvent(dirty *liquidStakingDi return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) } b.TypeIndex = newBtIdx - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -832,8 +854,7 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDi return errors.Wrapf(err, "get owner of candidate %s", delegateParam) } b.Delegate = delegateOwner.String() - dirty.putBucketInfo(tokenIDParam.Uint64(), b) - return nil + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } func (s *liquidStakingIndexer) handleWithdrawalEvent(dirty *liquidStakingDirty, event eventParam) error { @@ -842,15 +863,14 @@ func (s *liquidStakingIndexer) handleWithdrawalEvent(dirty *liquidStakingDirty, return err } - dirty.burnBucket(tokenIDParam.Uint64()) - return nil + return dirty.burnBucket(tokenIDParam.Uint64()) } func (s *liquidStakingIndexer) loadCache() error { delta := newLiquidStakingDelta() // load height var height uint64 - h, err := s.kvstore.Get(_liquidStakingHeightNS, _liquidStakingHeightKey) + h, err := s.kvstore.Get(_liquidStakingNS, _liquidStakingHeightKey) if err != nil { if !errors.Is(err, db.ErrNotExist) { return err @@ -862,6 +882,18 @@ func (s *liquidStakingIndexer) loadCache() error { } delta.putHeight(height) + // load total bucket count + var totalBucketCount uint64 + tbc, err := s.kvstore.Get(_liquidStakingNS, _liquidStakingTotalBucketCountKey) + if err != nil { + if !errors.Is(err, db.ErrNotExist) { + return err + } + } else { + totalBucketCount = byteutil.BytesToUint64BigEndian(tbc) + } + delta.putTotalBucketCount(totalBucketCount) + // load bucket info ks, vs, err := s.kvstore.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil { @@ -895,10 +927,11 @@ func (s *liquidStakingIndexer) loadCache() error { } func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { - if err := s.kvstore.WriteBatch(dirty.batch); err != nil { + batch, delta := dirty.finalize() + if err := s.kvstore.WriteBatch(batch); err != nil { return err } - if err := s.cache.merge(dirty.delta); err != nil { + if err := s.cache.merge(delta); err != nil { return err } return nil diff --git a/blockindex/util.go b/blockindex/util.go index e2f8c60463..307d183f37 100644 --- a/blockindex/util.go +++ b/blockindex/util.go @@ -10,8 +10,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/iotexproject/iotex-core/action" "github.com/pkg/errors" + + "github.com/iotexproject/iotex-core/action" ) type ( diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 6439e8c96d..2d67a2c01c 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1386,6 +1386,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.True(bt.UnstakeStartTime.IsZero()) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(1, indexer.TotalBucketCount()) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) @@ -1406,6 +1407,7 @@ func TestLiquidStaking(t *testing.T) { r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(1, indexer.TotalBucketCount()) t.Run("unstake", func(t *testing.T) { jumpBlocks(bc, 10, r) @@ -1427,6 +1429,7 @@ func TestLiquidStaking(t *testing.T) { r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.UnstakeStartTime.Unix()) r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(1, indexer.TotalBucketCount()) t.Run("withdraw", func(t *testing.T) { // freeze blocks are changed to 10 in test @@ -1450,6 +1453,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err = indexer.Bucket(uint64(tokenID)) r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) + r.EqualValues(1, indexer.TotalBucketCount()) }) }) }) From 0cb057d031f3942b0eb72c4ce1ad719b6a425a94 Mon Sep 17 00:00:00 2001 From: envestcc Date: Sat, 13 May 2023 10:06:41 +0800 Subject: [PATCH 33/51] add concurrency safety TODO --- blockindex/liquidstaking_delta.go | 4 ++-- blockindex/liquidstaking_indexer.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/blockindex/liquidstaking_delta.go b/blockindex/liquidstaking_delta.go index 3adf7b3851..20a77bb98c 100644 --- a/blockindex/liquidstaking_delta.go +++ b/blockindex/liquidstaking_delta.go @@ -51,10 +51,10 @@ var ( func (s deltaState) transfer(act deltaAction) (deltaState, error) { if _, ok := deltaStateTransferMap[s]; !ok { - return s, errors.New("invalid delta state") + return s, errors.Errorf("invalid delta state %d", s) } if _, ok := deltaStateTransferMap[s][act]; !ok { - return s, errors.New("invalid delta action") + return s, errors.Errorf("invalid delta action %d on state %d", act, s) } return deltaStateTransferMap[s][act], nil } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 2a219af156..b091a166f0 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -396,6 +396,7 @@ type ( // kvstore: persistent storage, used to initialize index cache at startup // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. + // TODO (iip-13): make it concurrent safe liquidStakingIndexer struct { kvstore db.KVStore // persistent storage cache *liquidStakingCache // in-memory index for clean data From 084b3c8205c231dfdbb47458c98f8838e616e6d1 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 15 May 2023 15:42:20 +0800 Subject: [PATCH 34/51] use interface to read & write on cache --- blockindex/liquidstaking_cache.go | 41 ++++++++++++++++++++++++++++- blockindex/liquidstaking_delta.go | 28 +++++++++++++------- blockindex/liquidstaking_dirty.go | 20 ++++---------- blockindex/liquidstaking_indexer.go | 10 +++---- 4 files changed, 69 insertions(+), 30 deletions(-) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 2c16977f67..331b78cd53 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -11,6 +11,33 @@ import ( ) type ( + // liquidStakingCacheReader is the interface to read liquid staking cache + // it serves the purpose of preventing modifications to it. + liquidStakingCacheReader interface { + getHeight() uint64 + getTotalBucketCount() uint64 + getTotalBucketTypeCount() uint64 + getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) + getBucketType(id uint64) (*BucketType, bool) + getBucketInfo(id uint64) (*BucketInfo, bool) + mustGetBucketType(id uint64) *BucketType + mustGetBucketInfo(id uint64) *BucketInfo + getAllBucketInfo() map[uint64]*BucketInfo + getCandidateVotes(ownerAddr string) *big.Int + } + + // liquidStakingCacheManager is the interface to manage liquid staking cache + // it's used to hide internal data, ensuring thread safety when used within the package + liquidStakingCacheManager interface { + liquidStakingCacheReader + merge(delta *liquidStakingDelta) error + putHeight(h uint64) + putTotalBucketCount(cnt uint64) + putBucketType(id uint64, bt *BucketType) + putBucketInfo(id uint64, bi *BucketInfo) + deleteBucketInfo(id uint64) + } + liquidStakingCache struct { idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket @@ -21,7 +48,7 @@ type ( } ) -func newLiquidStakingCache() *liquidStakingCache { +func newLiquidStakingCache() liquidStakingCacheManager { return &liquidStakingCache{ idBucketMap: make(map[uint64]*BucketInfo), idBucketTypeMap: make(map[uint64]*BucketType), @@ -134,3 +161,15 @@ func (s *liquidStakingCache) putTotalBucketCount(count uint64) { func (s *liquidStakingCache) getTotalBucketCount() uint64 { return s.totalBucketCount } + +func (s *liquidStakingCache) getTotalBucketTypeCount() uint64 { + return uint64(len(s.idBucketTypeMap)) +} + +func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*BucketInfo { + m := make(map[uint64]*BucketInfo) + for k, v := range s.idBucketMap { + m[k] = v + } + return m +} diff --git a/blockindex/liquidstaking_delta.go b/blockindex/liquidstaking_delta.go index 20a77bb98c..71f1a0a0cf 100644 --- a/blockindex/liquidstaking_delta.go +++ b/blockindex/liquidstaking_delta.go @@ -23,7 +23,7 @@ type ( deltaAction int liquidStakingDelta struct { - *liquidStakingCache // easy to query buckets + liquidStakingCacheManager // easy to query buckets bucketTypeDeltaState map[uint64]deltaState bucketInfoDeltaState map[uint64]deltaState @@ -61,9 +61,9 @@ func (s deltaState) transfer(act deltaAction) (deltaState, error) { func newLiquidStakingDelta() *liquidStakingDelta { return &liquidStakingDelta{ - liquidStakingCache: newLiquidStakingCache(), - bucketTypeDeltaState: make(map[uint64]deltaState), - bucketInfoDeltaState: make(map[uint64]deltaState), + liquidStakingCacheManager: newLiquidStakingCache(), + bucketTypeDeltaState: make(map[uint64]deltaState), + bucketInfoDeltaState: make(map[uint64]deltaState), } } @@ -77,7 +77,7 @@ func (s *liquidStakingDelta) addBucketType(id uint64, bt *BucketType) error { return err } } - s.liquidStakingCache.putBucketType(id, bt) + s.liquidStakingCacheManager.putBucketType(id, bt) return nil } @@ -91,7 +91,7 @@ func (s *liquidStakingDelta) updateBucketType(id uint64, bt *BucketType) error { return err } } - s.liquidStakingCache.putBucketType(id, bt) + s.liquidStakingCacheManager.putBucketType(id, bt) return nil } @@ -105,7 +105,7 @@ func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *BucketInfo) error { return err } } - s.liquidStakingCache.putBucketInfo(id, bi) + s.liquidStakingCacheManager.putBucketInfo(id, bi) return nil } @@ -119,7 +119,7 @@ func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *BucketInfo) error { return err } } - s.liquidStakingCache.putBucketInfo(id, bi) + s.liquidStakingCacheManager.putBucketInfo(id, bi) return nil } @@ -133,7 +133,7 @@ func (s *liquidStakingDelta) deleteBucketInfo(id uint64) error { return err } } - s.liquidStakingCache.deleteBucketInfo(id) + s.liquidStakingCacheManager.deleteBucketInfo(id) return nil } @@ -147,6 +147,16 @@ func (s *liquidStakingDelta) addedBucketCnt() uint64 { return addedBucketCnt } +func (s *liquidStakingDelta) addedBucketTypeCnt() uint64 { + cnt := uint64(0) + for _, state := range s.bucketTypeDeltaState { + if state == deltaStateAdded { + cnt++ + } + } + return cnt +} + func (s *liquidStakingDelta) isBucketDeleted(id uint64) bool { if _, ok := s.bucketInfoDeltaState[id]; ok { return s.bucketInfoDeltaState[id] == deltaStateRemoved diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index e78819e32e..9a2ebd71cd 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -21,15 +21,15 @@ type ( // 2. get up-to-date bucket // 3. store delta to merge to clean cache liquidStakingDirty struct { - clean *liquidStakingCache // clean cache to get buckets of last block - delta *liquidStakingDelta // delta for cache to store buckets of current block - batch batch.KVStoreBatch // batch for db to store buckets of current block + clean liquidStakingCacheReader // clean cache to get buckets of last block + delta *liquidStakingDelta // delta for cache to store buckets of current block + batch batch.KVStoreBatch // batch for db to store buckets of current block tokenOwner map[uint64]string once sync.Once } ) -func newLiquidStakingDirty(clean *liquidStakingCache) *liquidStakingDirty { +func newLiquidStakingDirty(clean liquidStakingCacheReader) *liquidStakingDirty { return &liquidStakingDirty{ clean: clean, delta: newLiquidStakingDelta(), @@ -96,17 +96,7 @@ func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration time.D } func (s *liquidStakingDirty) getBucketTypeCount() uint64 { - base := len(s.clean.idBucketTypeMap) - add := 0 - for k, dbt := range s.delta.idBucketTypeMap { - _, ok := s.clean.idBucketTypeMap[k] - if dbt != nil && !ok { - add++ - } else if dbt == nil && ok { - add-- - } - } - return uint64(base + add) + return s.clean.getTotalBucketTypeCount() + s.delta.addedBucketTypeCnt() } func (s *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index b091a166f0..6a940fd0a1 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -398,8 +398,8 @@ type ( // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. // TODO (iip-13): make it concurrent safe liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *liquidStakingCache // in-memory index for clean data + kvstore db.KVStore // persistent storage + cache liquidStakingCacheManager // in-memory index for clean data blockInterval time.Duration candNameToOwnerFunc candNameToOwnerFunc } @@ -507,7 +507,7 @@ func (s *liquidStakingIndexer) CandidateVotes(ownerAddr string) *big.Int { // Buckets returns the buckets func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { vbs := []*Bucket{} - for id, bi := range s.cache.idBucketMap { + for id, bi := range s.cache.getAllBucketInfo() { bt := s.cache.mustGetBucketType(bi.TypeIndex) vb, err := s.convertToVoteBucket(id, bi, bt) if err != nil { @@ -520,7 +520,7 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { // Bucket returns the bucket func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { - bi, ok := s.cache.idBucketMap[id] + bi, ok := s.cache.getBucketInfo(id) if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) } @@ -536,7 +536,7 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*Bucket, error) { vbs := make([]*Bucket, 0, len(indices)) for _, id := range indices { - bi, ok := s.cache.idBucketMap[id] + bi, ok := s.cache.getBucketInfo(id) if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) } From 7d408751883c60402846da12816e08da68251e63 Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 15 May 2023 17:08:10 +0800 Subject: [PATCH 35/51] make cache thread-safe --- blockindex/liquidstaking_cache.go | 140 ++++++++++++++++++++++++- blockindex/liquidstaking_cache_test.go | 40 +++++++ blockindex/liquidstaking_dirty.go | 18 ---- blockindex/liquidstaking_indexer.go | 11 +- 4 files changed, 185 insertions(+), 24 deletions(-) create mode 100644 blockindex/liquidstaking_cache_test.go diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 331b78cd53..e39972c723 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -7,6 +7,7 @@ package blockindex import ( "math/big" + "sync" "time" ) @@ -46,15 +47,21 @@ type ( height uint64 totalBucketCount uint64 // total number of buckets including burned buckets } + + liquidStakingCacheThreadSafety struct { + cache liquidStakingCacheManager + mutex sync.RWMutex + } ) -func newLiquidStakingCache() liquidStakingCacheManager { - return &liquidStakingCache{ +func newLiquidStakingCache() *liquidStakingCacheThreadSafety { + cache := &liquidStakingCache{ idBucketMap: make(map[uint64]*BucketInfo), idBucketTypeMap: make(map[uint64]*BucketType), propertyBucketTypeMap: make(map[int64]map[int64]uint64), candidateBucketMap: make(map[string]map[uint64]bool), } + return &liquidStakingCacheThreadSafety{cache: cache} } func (s *liquidStakingCache) putHeight(h uint64) { @@ -173,3 +180,132 @@ func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*BucketInfo { } return m } + +func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { + for id, state := range delta.bucketTypeDeltaState { + if state == deltaStateAdded || state == deltaStateModified { + s.putBucketType(id, delta.mustGetBucketType(id)) + } + } + for id, state := range delta.bucketInfoDeltaState { + if state == deltaStateAdded || state == deltaStateModified { + s.putBucketInfo(id, delta.mustGetBucketInfo(id)) + } else if state == deltaStateRemoved { + s.deleteBucketInfo(id) + } + } + s.putHeight(delta.getHeight()) + s.putTotalBucketCount(s.getTotalBucketCount() + delta.addedBucketCnt()) + return nil +} + +func (s *liquidStakingCacheThreadSafety) putHeight(h uint64) { + s.mutex.Lock() + defer s.mutex.Unlock() + s.cache.putHeight(h) +} + +func (s *liquidStakingCacheThreadSafety) getHeight() uint64 { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getHeight() +} + +func (s *liquidStakingCacheThreadSafety) putBucketType(id uint64, bt *BucketType) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.cache.putBucketType(id, bt) +} + +func (s *liquidStakingCacheThreadSafety) putBucketInfo(id uint64, bi *BucketInfo) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.cache.putBucketInfo(id, bi) +} + +func (s *liquidStakingCacheThreadSafety) deleteBucketInfo(id uint64) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.cache.deleteBucketInfo(id) +} + +func (s *liquidStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getBucketTypeIndex(amount, duration) +} + +func (s *liquidStakingCacheThreadSafety) getBucketType(id uint64) (*BucketType, bool) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getBucketType(id) +} + +func (s *liquidStakingCacheThreadSafety) mustGetBucketType(id uint64) *BucketType { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.mustGetBucketType(id) +} + +func (s *liquidStakingCacheThreadSafety) getBucketInfo(id uint64) (*BucketInfo, bool) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getBucketInfo(id) +} + +func (s *liquidStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *BucketInfo { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.mustGetBucketInfo(id) +} + +func (s *liquidStakingCacheThreadSafety) getCandidateVotes(ownerAddr string) *big.Int { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getCandidateVotes(ownerAddr) +} + +func (s *liquidStakingCacheThreadSafety) putTotalBucketCount(count uint64) { + s.mutex.Lock() + defer s.mutex.Unlock() + + s.cache.putTotalBucketCount(count) +} + +func (s *liquidStakingCacheThreadSafety) getTotalBucketCount() uint64 { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getTotalBucketCount() +} + +func (s *liquidStakingCacheThreadSafety) getTotalBucketTypeCount() uint64 { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getTotalBucketTypeCount() +} + +func (s *liquidStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*BucketInfo { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getAllBucketInfo() +} + +func (s *liquidStakingCacheThreadSafety) merge(delta *liquidStakingDelta) error { + s.mutex.Lock() + defer s.mutex.Unlock() + + return s.cache.merge(delta) +} diff --git a/blockindex/liquidstaking_cache_test.go b/blockindex/liquidstaking_cache_test.go new file mode 100644 index 0000000000..e745ee709d --- /dev/null +++ b/blockindex/liquidstaking_cache_test.go @@ -0,0 +1,40 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "math/big" + "sync" + "testing" + "time" +) + +func TestLiquidStakingCacheThreadSafety(t *testing.T) { + cache := newLiquidStakingCache() + + wait := sync.WaitGroup{} + wait.Add(2) + go func() { + for i := 0; i < 1000; i++ { + cache.putBucketType(uint64(i), &BucketType{ + Amount: big.NewInt(int64(i)), + Duration: time.Hour, + ActivatedAt: time.Now(), + }) + } + wait.Done() + }() + + go func() { + for i := 0; i < 1000; i++ { + cache.getBucketType(uint64(i)) + } + wait.Done() + }() + + wait.Wait() + // no panic means thread safety +} diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 9a2ebd71cd..97b210339c 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -38,24 +38,6 @@ func newLiquidStakingDirty(clean liquidStakingCacheReader) *liquidStakingDirty { } } -func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { - for id, state := range delta.bucketTypeDeltaState { - if state == deltaStateAdded || state == deltaStateModified { - s.putBucketType(id, delta.mustGetBucketType(id)) - } - } - for id, state := range delta.bucketInfoDeltaState { - if state == deltaStateAdded || state == deltaStateModified { - s.putBucketInfo(id, delta.mustGetBucketInfo(id)) - } else if state == deltaStateRemoved { - s.deleteBucketInfo(id) - } - } - s.putHeight(delta.getHeight()) - s.putTotalBucketCount(s.getTotalBucketCount() + delta.addedBucketCnt()) - return nil -} - func (s *liquidStakingDirty) putHeight(h uint64) { s.batch.Put(_liquidStakingNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") s.delta.putHeight(h) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 6a940fd0a1..7bc772ba91 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -398,8 +398,8 @@ type ( // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. // TODO (iip-13): make it concurrent safe liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache liquidStakingCacheManager // in-memory index for clean data + kvstore db.KVStore // persistent storage + cache *liquidStakingCacheThreadSafety // in-memory index for clean data blockInterval time.Duration candNameToOwnerFunc candNameToOwnerFunc } @@ -453,9 +453,12 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { // PutBlock puts a block into indexer func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { - // new dirty cache - dirty := newLiquidStakingDirty(s.cache) + // new dirty cache for this block + // it's not necessary to use thread safe cache here, because only one thread will call this function + // and no update to cache will happen before dirty merge to clean + dirty := newLiquidStakingDirty(s.cache.cache) dirty.putHeight(blk.Height()) + // make action map actionMap := make(map[hash.Hash256]*action.SealedEnvelope) for i := range blk.Actions { From 0140551a05ebef11cea27de80183829361c0f00c Mon Sep 17 00:00:00 2001 From: envestcc Date: Mon, 15 May 2023 17:18:23 +0800 Subject: [PATCH 36/51] remove thread-safety todo --- blockindex/liquidstaking_indexer.go | 1 - 1 file changed, 1 deletion(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 7bc772ba91..279e2e3e09 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -396,7 +396,6 @@ type ( // kvstore: persistent storage, used to initialize index cache at startup // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. - // TODO (iip-13): make it concurrent safe liquidStakingIndexer struct { kvstore db.KVStore // persistent storage cache *liquidStakingCacheThreadSafety // in-memory index for clean data From 13f59c17377cd4b3e9b86077a43f92a80fbba891 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 16 May 2023 19:08:17 +0800 Subject: [PATCH 37/51] use address instead of candidate name --- blockindex/liquidstaking_bucket.go | 21 +++-- blockindex/liquidstaking_cache.go | 22 ++--- blockindex/liquidstaking_dirty.go | 6 +- blockindex/liquidstaking_indexer.go | 60 +++++-------- blockindex/util.go | 14 +++- e2etest/liquid_staking_test.go | 126 +++++++++++++--------------- 6 files changed, 119 insertions(+), 130 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index d2067e2603..b22726599b 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -13,6 +13,8 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockindex/indexpb" "github.com/iotexproject/iotex-core/pkg/util/byteutil" @@ -25,8 +27,8 @@ type ( CreatedAt time.Time UnlockedAt time.Time UnstakedAt time.Time - Delegate string // owner address of the delegate - Owner string + Delegate address.Address // owner address of the delegate + Owner address.Address } // BucketType is the bucket type @@ -74,9 +76,9 @@ func (bt *BucketType) deserialize(b []byte) error { func (bi *BucketInfo) toProto() *indexpb.BucketInfo { pb := &indexpb.BucketInfo{ TypeIndex: bi.TypeIndex, - Delegate: bi.Delegate, + Delegate: bi.Delegate.String(), CreatedAt: timestamppb.New(bi.CreatedAt), - Owner: bi.Owner, + Owner: bi.Owner.String(), } if !bi.UnlockedAt.IsZero() { pb.UnlockedAt = timestamppb.New(bi.UnlockedAt) @@ -101,6 +103,7 @@ func (bi *BucketInfo) deserialize(b []byte) error { } func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { + var err error bi.TypeIndex = p.TypeIndex bi.CreatedAt = p.CreatedAt.AsTime() if p.UnlockedAt != nil { @@ -113,7 +116,13 @@ func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { } else { bi.UnstakedAt = time.Time{} } - bi.Delegate = p.Delegate - bi.Owner = p.Owner + bi.Delegate, err = address.FromString(p.Delegate) + if err != nil { + return err + } + bi.Owner, err = address.FromString(p.Owner) + if err != nil { + return err + } return nil } diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index e39972c723..8619635ea1 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -9,6 +9,8 @@ import ( "math/big" "sync" "time" + + "github.com/iotexproject/iotex-address/address" ) type ( @@ -24,7 +26,7 @@ type ( mustGetBucketType(id uint64) *BucketType mustGetBucketInfo(id uint64) *BucketInfo getAllBucketInfo() map[uint64]*BucketInfo - getCandidateVotes(ownerAddr string) *big.Int + getCandidateVotes(candidate address.Address) *big.Int } // liquidStakingCacheManager is the interface to manage liquid staking cache @@ -85,10 +87,10 @@ func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { s.idBucketMap[id] = bi - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { - s.candidateBucketMap[bi.Delegate] = make(map[uint64]bool) + if _, ok := s.candidateBucketMap[bi.Delegate.String()]; !ok { + s.candidateBucketMap[bi.Delegate.String()] = make(map[uint64]bool) } - s.candidateBucketMap[bi.Delegate][id] = true + s.candidateBucketMap[bi.Delegate.String()][id] = true } func (s *liquidStakingCache) deleteBucketInfo(id uint64) { @@ -97,10 +99,10 @@ func (s *liquidStakingCache) deleteBucketInfo(id uint64) { return } delete(s.idBucketMap, id) - if _, ok := s.candidateBucketMap[bi.Delegate]; !ok { + if _, ok := s.candidateBucketMap[bi.Delegate.String()]; !ok { return } - delete(s.candidateBucketMap[bi.Delegate], id) + delete(s.candidateBucketMap[bi.Delegate.String()], id) } func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { @@ -138,9 +140,9 @@ func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *BucketInfo { return bt } -func (s *liquidStakingCache) getCandidateVotes(ownerAddr string) *big.Int { +func (s *liquidStakingCache) getCandidateVotes(candidate address.Address) *big.Int { votes := big.NewInt(0) - m, ok := s.candidateBucketMap[ownerAddr] + m, ok := s.candidateBucketMap[candidate.String()] if !ok { return votes } @@ -268,11 +270,11 @@ func (s *liquidStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *BucketInf return s.cache.mustGetBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) getCandidateVotes(ownerAddr string) *big.Int { +func (s *liquidStakingCacheThreadSafety) getCandidateVotes(candidate address.Address) *big.Int { s.mutex.RLock() defer s.mutex.RUnlock() - return s.cache.getCandidateVotes(ownerAddr) + return s.cache.getCandidateVotes(candidate) } func (s *liquidStakingCacheThreadSafety) putTotalBucketCount(count uint64) { diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 97b210339c..955372eb9c 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) @@ -24,7 +26,7 @@ type ( clean liquidStakingCacheReader // clean cache to get buckets of last block delta *liquidStakingDelta // delta for cache to store buckets of current block batch batch.KVStoreBatch // batch for db to store buckets of current block - tokenOwner map[uint64]string + tokenOwner map[uint64]address.Address once sync.Once } ) @@ -34,7 +36,7 @@ func newLiquidStakingDirty(clean liquidStakingCacheReader) *liquidStakingDirty { clean: clean, delta: newLiquidStakingDelta(), batch: batch.NewBatch(), - tokenOwner: make(map[uint64]string), + tokenOwner: make(map[uint64]address.Address), } } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 279e2e3e09..62d8c7f8bd 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -149,9 +149,9 @@ const ( }, { "indexed": false, - "internalType": "bytes12", + "internalType": "address", "name": "newDelegate", - "type": "bytes12" + "type": "address" } ], "name": "DelegateChanged", @@ -263,9 +263,9 @@ const ( }, { "indexed": false, - "internalType": "bytes12", + "internalType": "address", "name": "delegate", - "type": "bytes12" + "type": "address" }, { "indexed": false, @@ -379,7 +379,7 @@ type ( LiquidStakingIndexer interface { blockdao.BlockIndexer - CandidateVotes(ownerAddr string) *big.Int + CandidateVotes(candidate address.Address) *big.Int Buckets() ([]*Bucket, error) Bucket(id uint64) (*Bucket, error) BucketsByIndices(indices []uint64) ([]*Bucket, error) @@ -397,12 +397,10 @@ type ( // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *liquidStakingCacheThreadSafety // in-memory index for clean data - blockInterval time.Duration - candNameToOwnerFunc candNameToOwnerFunc + kvstore db.KVStore // persistent storage + cache *liquidStakingCacheThreadSafety // in-memory index for clean data + blockInterval time.Duration } - candNameToOwnerFunc func(name string) (address.Address, error) ) var ( @@ -425,12 +423,11 @@ func init() { } // NewLiquidStakingIndexer creates a new liquid staking indexer -func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration, candNameToOwnerFunc candNameToOwnerFunc) LiquidStakingIndexer { +func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) LiquidStakingIndexer { return &liquidStakingIndexer{ - blockInterval: blockInterval, - kvstore: kvStore, - cache: newLiquidStakingCache(), - candNameToOwnerFunc: candNameToOwnerFunc, + blockInterval: blockInterval, + kvstore: kvStore, + cache: newLiquidStakingCache(), } } @@ -502,8 +499,8 @@ func (s *liquidStakingIndexer) Height() (uint64, error) { } // CandidateVotes returns the candidate votes -func (s *liquidStakingIndexer) CandidateVotes(ownerAddr string) *big.Int { - return s.cache.getCandidateVotes(ownerAddr) +func (s *liquidStakingIndexer) CandidateVotes(candidate address.Address) *big.Int { + return s.cache.getCandidateVotes(candidate) } // Buckets returns the buckets @@ -611,7 +608,7 @@ func (s *liquidStakingIndexer) handleTransferEvent(dirty *liquidStakingDirty, ev return err } - dirty.tokenOwner[tokenID.Uint64()] = to.String() + dirty.tokenOwner[tokenID.Uint64()] = to return nil } @@ -668,7 +665,7 @@ func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, even if err != nil { return err } - delegateParam, err := event.fieldBytes12("delegate") + delegateParam, err := event.fieldAddress("delegate") if err != nil { return err } @@ -685,13 +682,9 @@ func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, even if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - delegateOwner, err := s.candNameToOwnerFunc(delegateParam) - if err != nil { - return errors.Wrapf(err, "get delegate owner from %v failed", delegateParam) - } bucket := BucketInfo{ TypeIndex: btIdx, - Delegate: delegateOwner.String(), + Delegate: delegateParam, Owner: dirty.tokenOwner[tokenIDParam.Uint64()], CreatedAt: timestamp, } @@ -843,7 +836,7 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDi if err != nil { return err } - delegateParam, err := event.fieldBytes12("newDelegate") + delegateParam, err := event.fieldAddress("newDelegate") if err != nil { return err } @@ -852,11 +845,7 @@ func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDi if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - delegateOwner, err := s.candNameToOwnerFunc(delegateParam) - if err != nil { - return errors.Wrapf(err, "get owner of candidate %s", delegateParam) - } - b.Delegate = delegateOwner.String() + b.Delegate = delegateParam return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } @@ -945,7 +934,6 @@ func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duratio } func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { - var err error vb := Bucket{ Index: token, StakedAmount: bt.Amount, @@ -954,14 +942,8 @@ func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, StakeStartTime: bi.CreatedAt, UnstakeStartTime: bi.UnstakedAt, AutoStake: bi.UnlockedAt.IsZero(), - } - vb.Candidate, err = address.FromString(bi.Delegate) - if err != nil { - return nil, err - } - vb.Owner, err = address.FromHex(bi.Owner) - if err != nil { - return nil, err + Candidate: bi.Delegate, + Owner: bi.Owner, } if !bi.UnlockedAt.IsZero() { vb.StakeStartTime = bi.UnlockedAt diff --git a/blockindex/util.go b/blockindex/util.go index 307d183f37..6202246c56 100644 --- a/blockindex/util.go +++ b/blockindex/util.go @@ -12,6 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/action" ) @@ -52,12 +54,16 @@ func (e eventParam) fieldUint256Slice(name string) ([]*big.Int, error) { return eventField[[]*big.Int](e, name) } -func (e eventParam) fieldAddress(name string) (common.Address, error) { - return eventField[common.Address](e, name) +func (e eventParam) fieldAddress(name string) (address.Address, error) { + commAddr, err := eventField[common.Address](e, name) + if err != nil { + return nil, err + } + return address.FromBytes(commAddr.Bytes()) } -func (e eventParam) indexedFieldAddress(name string) (common.Address, error) { - return eventField[common.Address](e, name) +func (e eventParam) indexedFieldAddress(name string) (address.Address, error) { + return e.fieldAddress(name) } func (e eventParam) indexedFieldUint256(name string) (*big.Int, error) { diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 2d67a2c01c..bc71e34415 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -11,9 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/iotexproject/go-pkgs/crypto" "github.com/iotexproject/go-pkgs/hash" - "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-proto/golang/iotextypes" - "github.com/pkg/errors" "github.com/stretchr/testify/require" "golang.org/x/exp/slices" @@ -39,7 +37,7 @@ import ( const ( // _liquidStakingContractByteCode is the byte code of the liquid staking contract for testing, which changes the freeze blocks to 10 - _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dc780620002776000396000f3fe6080604052600436106102925760003560e01c806378bfca101161015a578063c87b56dd116100c1578063e0028ecf1161007a578063e0028ecf146107dd578063e449f341146107fd578063e985e9c51461081d578063eb0ffb2e14610866578063f0b56b5d14610886578063f2fde38b1461089b57600080fd5b8063c87b56dd14610741578063c8e7792314610761578063cd0a02d014610781578063d0949f9914610794578063d6605fd8146107aa578063d6819bcc146107ca57600080fd5b8063a22cb46511610113578063a22cb4651461069b578063ad46fc64146106bb578063b2383e55146106db578063b88d4fde146106ee578063b8f4bd7b1461070e578063bbe33ea51461072e57600080fd5b806378bfca10146105f15780638456cb591461061e5780638da5cb5b1461063357806393b6ef591461065157806395d89b41146106715780639f7d5b001461068657600080fd5b806342842e0e116101fe5780635d36598f116101b75780635d36598f1461053c5780636198e3391461055c5780636352211e1461057c5780636faa5c271461059c57806370a08231146105bc578063715018a6146105dc57600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104ca578063597cc14a146104ea5780635c975abb146104fd5780635ceb8b5b1461051c57600080fd5b80631338736f116102505780631338736f1461039657806323b872dd146103b65780632dc83008146103d65780632e17de78146103f65780633f4ba83a146104165780633fac69af1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b236600461341b565b6108bb565b005b3480156102c557600080fd5b506102d96102d4366004613461565b610982565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e61030936600461347e565b6109d4565b6040519081526020016102e5565b34801561032857600080fd5b506103316109fa565b6040516102e591906134e7565b34801561034a57600080fd5b5061035e61035936600461347e565b610a8c565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046134fa565b610ab3565b3480156103a257600080fd5b506102b76103b1366004613526565b610bc8565b3480156103c257600080fd5b506102b76103d1366004613548565b610c3b565b3480156103e257600080fd5b506102b76103f13660046135a6565b610c6c565b34801561040257600080fd5b506102b761041136600461347e565b610cda565b34801561042257600080fd5b506102b7610d89565b34801561043757600080fd5b5061044b61044636600461361d565b610d9b565b6040516102e5919061365e565b34801561046457600080fd5b506102b7610473366004613548565b610f17565b34801561048457600080fd5b5061049861049336600461347e565b610f32565b6040805195865260208601949094529284019190915260608301526001600160a01b031916608082015260a0016102e5565b3480156104d657600080fd5b506102d96104e5366004613526565b610fa8565b61030e6104f83660046135a6565b610fc3565b34801561050957600080fd5b50600654600160a01b900460ff166102d9565b34801561052857600080fd5b506102b76105373660046136e8565b611039565b34801561054857600080fd5b506102b761055736600461361d565b6110e0565b34801561056857600080fd5b506102b761057736600461347e565b611176565b34801561058857600080fd5b5061035e61059736600461347e565b6111d8565b3480156105a857600080fd5b5061044b6105b736600461361d565b611238565b3480156105c857600080fd5b5061030e6105d7366004613733565b6113ac565b3480156105e857600080fd5b506102b7611432565b3480156105fd57600080fd5b5061061161060c366004613526565b611444565b6040516102e59190613750565b34801561062a57600080fd5b506102b7611579565b34801561063f57600080fd5b506006546001600160a01b031661035e565b34801561065d57600080fd5b5061030e61066c36600461347e565b611589565b34801561067d57600080fd5b506103316115b4565b34801561069257600080fd5b50600b5461030e565b3480156106a757600080fd5b506102b76106b63660046137a9565b6115c3565b3480156106c757600080fd5b506102b76106d63660046137dc565b6115d2565b6102b76106e9366004613526565b611669565b3480156106fa57600080fd5b506102b7610709366004613875565b611771565b34801561071a57600080fd5b506102b7610729366004613938565b6117a9565b6102b761073c3660046136e8565b611898565b34801561074d57600080fd5b5061033161075c36600461347e565b611a9f565b34801561076d57600080fd5b506102b761077c366004613526565b611b12565b61030e61078f36600461398e565b611cb7565b3480156107a057600080fd5b5061030e60001981565b3480156107b657600080fd5b506102b76107c5366004613526565b611d81565b61030e6107d83660046139cb565b611e6a565b3480156107e957600080fd5b506102b76107f8366004613526565b611f5c565b34801561080957600080fd5b506102b761081836600461361d565b611fd0565b34801561082957600080fd5b506102d9610838366004613a8c565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561087257600080fd5b506102b7610881366004613526565b6120ac565b34801561089257600080fd5b5061030e600a81565b3480156108a757600080fd5b506102b76108b6366004613733565b612122565b6108c361219b565b816108cd816121e8565b600083815260086020526040902060028101546108e99061223d565b156109335760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093c846122b1565b6109468184612354565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b357506001600160e01b03198216635b5e139f60e01b145b806109ce57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109df82612413565b6000828152600860205260409020600201546109ce9061223d565b606060008054610a0990613aba565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3590613aba565b8015610a825780601f10610a5757610100808354040283529160200191610a82565b820191906000526020600020905b815481529060010190602001808311610a6557829003601f168201915b5050505050905090565b6000610a9782612413565b506000908152600460205260409020546001600160a01b031690565b6000610abe826111d8565b9050806001600160a01b0316836001600160a01b031603610b2b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161092a565b336001600160a01b0382161480610b475750610b478133610838565b610bb95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161092a565b610bc38383612472565b505050565b610bd061219b565b81610bda816121e8565b6000838152600860205260409020610bf1816124e0565b610bfb818461252a565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c2d91815260200190565b60405180910390a250505050565b610c453382612612565b610c615760405162461bcd60e51b815260040161092a90613af4565b610bc3838383612690565b610c7461219b565b81610c7e816121e8565b6000838152600860205260409020610c969083612801565b6040516001600160a01b03198316815283907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a2505050565b610ce261219b565b80610cec816121e8565b6000828152600860205260409020610d03816124e0565b610d0c81612904565b15610d505760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b610d59816129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d916129e4565b610d99612a3e565b565b6060816001600160401b03811115610db557610db561382f565b604051908082528060200260200182016040528015610de857816020015b6060815260200190600190039081610dd35790505b5090506000610df6600b5490565b905060005b83811015610f0f57816001600160401b03811115610e1b57610e1b61382f565b604051908082528060200260200182016040528015610e44578160200160208202803683370190505b50838281518110610e5757610e57613b41565b6020026020010181905250600060096000878785818110610e7a57610e7a613b41565b9050602002016020810190610e8f9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b83811015610f05576000818152602083905260409020548551869085908110610ed957610ed9613b41565b60200260200101518281518110610ef257610ef2613b41565b6020908102919091010152600101610eae565b5050600101610dfb565b505092915050565b610bc383838360405180602001604052806000815250611771565b6000806000806000610f4386612413565b60008681526008602052604081208054600b80549293929091908110610f6b57610f6b613b41565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a5091985092965060a01b94509092505050565b6000610fbc610fb78484612a93565b612afa565b9392505050565b6000610fcd61219b565b346000610fda8286612a93565b9050610fe581612b2b565b610fef8185612b77565b60075460405181907f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a9061102890889087908b90613b72565b60405180910390a295945050505050565b61104161219b565b60008060005b848110156110d85785858281811061106157611061613b41565b905060200201359250611073836121e8565b6000838152600860205260409020915061108c826124e0565b611096828561252a565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b856040516110c891815260200190565b60405180910390a2600101611047565b505050505050565b6110e861219b565b60008060005b8381101561116f5784848281811061110857611108613b41565b90506020020135925061111a836121e8565b6000838152600860205260409020915061113382612c17565b61113c82612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a26001016110ee565b5050505050565b61117e61219b565b80611188816121e8565b600082815260086020526040902061119f81612c17565b6111a881612c61565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109ce5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b6060816001600160401b038111156112525761125261382f565b60405190808252806020026020018201604052801561128557816020015b60608152602001906001900390816112705790505b5090506000611293600b5490565b905060005b83811015610f0f57816001600160401b038111156112b8576112b861382f565b6040519080825280602002602001820160405280156112e1578160200160208202803683370190505b508382815181106112f4576112f4613b41565b60200260200101819052506000600a600087878581811061131757611317613b41565b905060200201602081019061132c9190613b57565b6001600160a01b03191681526020810191909152604001600090812091505b838110156113a257600081815260208390526040902054855186908590811061137657611376613b41565b6020026020010151828151811061138f5761138f613b41565b602090810291909101015260010161134b565b5050600101611298565b60006001600160a01b0382166114165760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161092a565b506001600160a01b031660009081526003602052604090205490565b61143a6129e4565b610d996000612cb9565b60606000821180156114615750600b5461145e8385613baa565b11155b61147d5760405162461bcd60e51b815260040161092a90613bbd565b816001600160401b038111156114955761149561382f565b6040519080825280602002602001820160405280156114ea57816020015b6114d760405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816114b35790505b50905060005b8281101561157257600b8185018154811061150d5761150d613b41565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061155657611556613b41565b602002602001018190525061156b8160010190565b90506114f0565b5092915050565b6115816129e4565b610d99612d0b565b600061159482612413565b60008281526008602052604090206115ab816124e0565b610fbc81612904565b606060018054610a0990613aba565b6115ce338383612d4e565b5050565b6115da61219b565b6000805b8381101561116f578484828181106115f8576115f8613b41565b90506020020135915061160a826121e8565b60008281526008602052604090206116229084612801565b6040516001600160a01b03198416815282907ffec7db38481afeb8686a62ee7bba420143bd43540fe5e57b7316be50bdaa220c9060200160405180910390a26001016115de565b61167161219b565b8161167b816121e8565b600083815260086020526040902061169281612c17565b8054600b805460009190839081106116ac576116ac613b41565b90600052602060002090600302019050848160000154346116cd9190613baa565b146116ea5760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a6020908152604080832085845290915290208054600019019055600181015461172f9084908790612e1c565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161176191815260200190565b60405180910390a2505050505050565b61177b3383612612565b6117975760405162461bcd60e51b815260040161092a90613af4565b6117a384848484612e6c565b50505050565b6117b161219b565b60008060005b848110156110d8578585828181106117d1576117d1613b41565b9050602002013592506117e3836121e8565b600083815260086020526040902060028101549092506118029061223d565b156118475760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b604482015260640161092a565b611850836122b1565b61185a8285612354565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016117b7565b6118a061219b565b600182116118e15760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b604482015260640161092a565b3460008080855b8015611a95576000190187878281811061190457611904613b41565b905060200201359350611916846121e8565b6000848152600860205260409020925061192f836124e0565b82546003840154600b805460a09290921b918390811061195157611951613b41565b9060005260206000209060030201935083600101548810156119a85760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b83546119b49088613baa565b96506119c68560010154600019141590565b156119fc576001600160a01b03198116600090815260096020908152604080832085845290915290208054600019019055611a29565b6001600160a01b031981166000908152600a60209081526040808320858452909152902080546000190190555b8215611a3d57611a38866122b1565b611a8e565b6000196001860155611a5085888a612e1c565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611a859493929190613c14565b60405180910390a15b50506118e8565b5050505050505050565b6060611aaa82612413565b6000611ac160408051602081019091526000815290565b90506000815111611ae15760405180602001604052806000815250610fbc565b80611aeb84612e9f565b604051602001611afc929190613c5a565b6040516020818303038152906040529392505050565b611b1a6129e4565b81600003611b5e5760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b604482015260640161092a565b6000828152600c6020908152604080832084845290915290205415611bbd5760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b604482015260640161092a565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b6000611cc161219b565b600082118015611cd9575034611cd78387613c89565b145b611cf55760405162461bcd60e51b815260040161092a90613bbd565b6000611d018686612a93565b9050611d0c81612b2b565b600754600101915060005b83811015611d7657611d298286612b77565b611d338184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a868989604051611d6693929190613b72565b60405180910390a2600101611d17565b50505b949350505050565b611d8961219b565b81611d93816121e8565b6000838152600860205260409020611daa81612c17565b8054600b80546000919083908110611dc457611dc4613b41565b9060005260206000209060030201905080600101548511611df75760405162461bcd60e51b815260040161092a90613be9565b600383015460a01b6001600160a01b0319166000908152600a60209081526040808320858452909152902080546000190190558054611e3890849087612e1c565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161176191815260200190565b6000611e7461219b565b34825185611e829190613c89565b14611e9f5760405162461bcd60e51b815260040161092a90613bbd565b6000611eab8585612a93565b9050611eb681612b2b565b600754600101915060005b8351811015611f5357611eed82858381518110611ee057611ee0613b41565b6020026020010151612b77565b611ef78184613baa565b7f1f44b78b04f7c6f80fc97ae8b196d9e9d7a81663114744f18fe5d073cd70ce4a858381518110611f2a57611f2a613b41565b60200260200101518888604051611f4393929190613b72565b60405180910390a2600101611ec1565b50509392505050565b611f646129e4565b43600b611f718484612a93565b81548110611f8157611f81613b41565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611cab929190918252602082015260400190565b611fd861219b565b60008060005b8381101561116f57848482818110611ff857611ff8613b41565b90506020020135925061200a836121e8565b60008381526008602052604090209150612023826124e0565b61202c82612904565b156120705760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b604482015260640161092a565b612079826129a9565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611fde565b6120b46129e4565b600019600b6120c38484612a93565b815481106120d3576120d3613b41565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611cab929190918252602082015260400190565b61212a6129e4565b6001600160a01b03811661218f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092a565b61219881612cb9565b50565b600654600160a01b900460ff1615610d995760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161092a565b6121f1816111d8565b6001600160a01b0316336001600160a01b0316146121985760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b604482015260640161092a565b600060001982036122895760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b604482015260640161092a565b6000612296600a84613baa565b90504381116122a85750600092915050565b43900392915050565b60006122bc826111d8565b90506122cc816000846001612f31565b6122d5826111d8565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b83600001548154811061236d5761236d613b41565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d80600081146123c8576040519150601f19603f3d011682016040523d82523d6000602084013e6123cd565b606091505b50509050806117a35760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b604482015260640161092a565b6000818152600260205260409020546001600160a01b03166121985760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161092a565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124a7826111d8565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6002810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b604482015260640161092a565b8154600383015460a01b61253d84612904565b83101561257f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b604482015260640161092a565b60006125af600b848154811061259757612597613b41565b90600052602060002090600302016000015485612a93565b90506125ba81612b2b565b60001960018681018290556001600160a01b03199390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061261e836111d8565b9050806001600160a01b0316846001600160a01b0316148061266557506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80611d795750836001600160a01b031661267e84610a8c565b6001600160a01b031614949350505050565b826001600160a01b03166126a3826111d8565b6001600160a01b0316146126c95760405162461bcd60e51b815260040161092a90613ca0565b6001600160a01b03821661272b5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161092a565b6127388383836001612f31565b826001600160a01b031661274b826111d8565b6001600160a01b0316146127715760405162461bcd60e51b815260040161092a90613ca0565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61280a826124e0565b8154600383015460a01b6001600160a01b0319808416908216036128405760405162461bcd60e51b815260040161092a90613be9565b600184015460001914612897576001600160a01b03198181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556128dd565b6001600160a01b03198181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546bffffffffffffffffffffffff191660a09290921c919091179055565b600181015460009060001981036129565760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b604482015260640161092a565b6000600b84600001548154811061296f5761296f613b41565b9060005260206000209060030201600101548261298c9190613baa565b905043811161299f575060009392505050565b4390039392505050565b436002820155600381015460a01b6001600160a01b031916600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d995760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161092a565b612a46612ffa565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612af05760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b604482015260640161092a565b6000198101611d79565b600043600b8381548110612b1057612b10613b41565b90600052602060002090600302016002015411159050919050565b612b3481612afa565b6121985760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b604482015260640161092a565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0319891660608501818152600097885260088452868820955186559151858901559251600285015551600390930180546bffffffffffffffffffffffff191660a09490941c939093179092558352600a81528183208784529052902080549091019055546115ce90339061304a565b6001810154600019146121985760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b604482015260640161092a565b805460038201544360019384015560a01b6001600160a01b0319166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d1361219b565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a763390565b816001600160a01b0316836001600160a01b031603612daf5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161092a565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e288383612a93565b9050612e3381612b2b565b600384015460a01b6001600160a01b0319166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e77848484612690565b612e8384848484613064565b6117a35760405162461bcd60e51b815260040161092a90613ce5565b60606000612eac83613162565b60010190506000816001600160401b03811115612ecb57612ecb61382f565b6040519080825280601f01601f191660200182016040528015612ef5576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612eff57509392505050565b80600114612f815760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f7274656400604482015260640161092a565b6001600160a01b0383161580612fa95750600082815260086020526040902060020154600019145b612ff55760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e0000604482015260640161092a565b6117a3565b600654600160a01b900460ff16610d995760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161092a565b6115ce82826040518060200160405280600081525061323a565b60006001600160a01b0384163b1561315a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130a8903390899088908890600401613d37565b6020604051808303816000875af19250505080156130e3575060408051601f3d908101601f191682019092526130e091810190613d74565b60015b613140573d808015613111576040519150601f19603f3d011682016040523d82523d6000602084013e613116565b606091505b5080516000036131385760405162461bcd60e51b815260040161092a90613ce5565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611d79565b506001611d79565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131a15772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131cd576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106131eb57662386f26fc10000830492506010015b6305f5e1008310613203576305f5e100830492506008015b612710831061321757612710830492506004015b60648310613229576064830492506002015b600a83106109ce5760010192915050565b613244838361326d565b6132516000848484613064565b610bc35760405162461bcd60e51b815260040161092a90613ce5565b6001600160a01b0382166132c35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161092a565b6000818152600260205260409020546001600160a01b0316156133285760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b613336600083836001612f31565b6000818152600260205260409020546001600160a01b03161561339b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161092a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b038116811461219857600080fd5b6000806040838503121561342e57600080fd5b82359150602083013561344081613406565b809150509250929050565b6001600160e01b03198116811461219857600080fd5b60006020828403121561347357600080fd5b8135610fbc8161344b565b60006020828403121561349057600080fd5b5035919050565b60005b838110156134b257818101518382015260200161349a565b50506000910152565b600081518084526134d3816020860160208601613497565b601f01601f19169290920160200192915050565b602081526000610fbc60208301846134bb565b6000806040838503121561350d57600080fd5b823561351881613406565b946020939093013593505050565b6000806040838503121561353957600080fd5b50508035926020909101359150565b60008060006060848603121561355d57600080fd5b833561356881613406565b9250602084013561357881613406565b929592945050506040919091013590565b80356001600160a01b0319811681146135a157600080fd5b919050565b600080604083850312156135b957600080fd5b823591506135c960208401613589565b90509250929050565b60008083601f8401126135e457600080fd5b5081356001600160401b038111156135fb57600080fd5b6020830191508360208260051b850101111561361657600080fd5b9250929050565b6000806020838503121561363057600080fd5b82356001600160401b0381111561364657600080fd5b613652858286016135d2565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b838110156136da57888603603f19018552825180518088529088019088880190845b818110156136c45783518352928a0192918a01916001016136a8565b5090975050509386019391860191600101613686565b509398975050505050505050565b6000806000604084860312156136fd57600080fd5b83356001600160401b0381111561371357600080fd5b61371f868287016135d2565b909790965060209590950135949350505050565b60006020828403121561374557600080fd5b8135610fbc81613406565b602080825282518282018190526000919060409081850190868401855b8281101561379c578151805185528681015187860152850151858501526060909301929085019060010161376d565b5091979650505050505050565b600080604083850312156137bc57600080fd5b82356137c781613406565b91506020830135801515811461344057600080fd5b6000806000604084860312156137f157600080fd5b83356001600160401b0381111561380757600080fd5b613813868287016135d2565b9094509250613826905060208501613589565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561386d5761386d61382f565b604052919050565b6000806000806080858703121561388b57600080fd5b843561389681613406565b93506020858101356138a781613406565b93506040860135925060608601356001600160401b03808211156138ca57600080fd5b818801915088601f8301126138de57600080fd5b8135818111156138f0576138f061382f565b613902601f8201601f19168501613845565b9150808252898482850101111561391857600080fd5b808484018584013760008482840101525080935050505092959194509250565b60008060006040848603121561394d57600080fd5b83356001600160401b0381111561396357600080fd5b61396f868287016135d2565b909450925050602084013561398381613406565b809150509250925092565b600080600080608085870312156139a457600080fd5b84359350602085013592506139bb60408601613589565b9396929550929360600135925050565b6000806000606084860312156139e057600080fd5b83359250602080850135925060408501356001600160401b0380821115613a0657600080fd5b818701915087601f830112613a1a57600080fd5b813581811115613a2c57613a2c61382f565b8060051b9150613a3d848301613845565b818152918301840191848101908a841115613a5757600080fd5b938501935b83851015613a7c57613a6d85613589565b82529385019390850190613a5c565b8096505050505050509250925092565b60008060408385031215613a9f57600080fd5b8235613aaa81613406565b9150602083013561344081613406565b600181811c90821680613ace57607f821691505b602082108103613aee57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613b6957600080fd5b610fbc82613589565b6001600160a01b03199390931683526020830191909152604082015260600190565b634e487b7160e01b600052601160045260246000fd5b808201808211156109ce576109ce613b94565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3457600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6c818460208801613497565b835190830190613c80818360208801613497565b01949350505050565b80820281158282048414176109ce576109ce613b94565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d6a908301846134bb565b9695505050505050565b600060208284031215613d8657600080fd5b8151610fbc8161344b56fea264697066735822122033a72ba2419a7cb3b00b4b4de4305d6458e98ea74f8be8cc9c16afc85a97571764736f6c63430008130033` + _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c80637acb77571161015a578063bbe33ea5116100c1578063e449f3411161007a578063e449f341146107e9578063e985e9c514610809578063eb0ffb2e14610852578063eec7ee7314610872578063f0b56b5d14610885578063f2fde38b1461089a57600080fd5b8063bbe33ea514610740578063c87b56dd14610753578063c8e7792314610773578063d0949f9914610793578063d6605fd8146107a9578063e0028ecf146107c957600080fd5b806398ca3b761161011357806398ca3b76146106985780639f7d5b00146106b8578063a22cb465146106cd578063b2383e55146106ed578063b88d4fde14610700578063b8f4bd7b1461072057600080fd5b80637acb7757146105fd5780638456cb59146106105780638da5cb5b1461062557806393b6ef591461064357806395d89b4114610663578063960014bd1461067857600080fd5b806342842e0e116101fe5780636198e339116101b75780636198e339146105485780636352211e1461056857806370a0823114610588578063711563d4146105a8578063715018a6146105bb57806378bfca10146105d057600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104c95780635c975abb146104e95780635ceb8b5b146105085780635d36598f1461052857600080fd5b80630f5b2ca5116102505780630f5b2ca5146103965780631338736f146103b657806323b872dd146103d65780632e17de78146103f65780633f4ba83a146104165780633fd140df1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b23660046134d2565b6108ba565b005b3480156102c557600080fd5b506102d96102d4366004613518565b610981565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613535565b6109d3565b6040519081526020016102e5565b34801561032857600080fd5b506103316109f9565b6040516102e5919061359e565b34801561034a57600080fd5b5061035e610359366004613535565b610a8b565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046135b1565b610ab2565b3480156103a257600080fd5b506102b76103b13660046134d2565b610bc7565b3480156103c257600080fd5b506102b76103d13660046135dd565b610c34565b3480156103e257600080fd5b506102b76103f13660046135ff565b610ca7565b34801561040257600080fd5b506102b7610411366004613535565b610cd8565b34801561042257600080fd5b506102b7610d87565b34801561043757600080fd5b5061044b61044636600461368b565b610d99565b6040516102e591906136cc565b34801561046457600080fd5b506102b76104733660046135ff565b610f1b565b34801561048457600080fd5b50610498610493366004613535565b610f36565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a0016102e5565b3480156104d557600080fd5b506102d96104e43660046135dd565b610fb2565b3480156104f557600080fd5b50600654600160a01b900460ff166102d9565b34801561051457600080fd5b506102b7610523366004613756565b610fcd565b34801561053457600080fd5b506102b761054336600461368b565b611074565b34801561055457600080fd5b506102b7610563366004613535565b61110a565b34801561057457600080fd5b5061035e610583366004613535565b61116c565b34801561059457600080fd5b5061030e6105a33660046137a1565b6111cc565b61030e6105b63660046137be565b611252565b3480156105c757600080fd5b506102b761132b565b3480156105dc57600080fd5b506105f06105eb3660046135dd565b61133d565b6040516102e591906137fd565b61030e61060b3660046134d2565b611472565b34801561061c57600080fd5b506102b76114f6565b34801561063157600080fd5b506006546001600160a01b031661035e565b34801561064f57600080fd5b5061030e61065e366004613535565b611506565b34801561066f57600080fd5b50610331611531565b34801561068457600080fd5b5061044b61069336600461368b565b611540565b3480156106a457600080fd5b506102b76106b3366004613856565b6116ba565b3480156106c457600080fd5b50600b5461030e565b3480156106d957600080fd5b506102b76106e83660046138ac565b611750565b6102b76106fb3660046135dd565b61175f565b34801561070c57600080fd5b506102b761071b366004613925565b611863565b34801561072c57600080fd5b506102b761073b366004613856565b61189b565b6102b761074e366004613756565b61198a565b34801561075f57600080fd5b5061033161076e366004613535565b611b94565b34801561077f57600080fd5b506102b761078e3660046135dd565b611c07565b34801561079f57600080fd5b5061030e60001981565b3480156107b557600080fd5b506102b76107c43660046135dd565b611dac565b3480156107d557600080fd5b506102b76107e43660046135dd565b611e91565b3480156107f557600080fd5b506102b761080436600461368b565b611f05565b34801561081557600080fd5b506102d96108243660046139e8565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561085e57600080fd5b506102b761086d3660046135dd565b611fe1565b61030e610880366004613a16565b612057565b34801561089157600080fd5b5061030e600a81565b3480156108a657600080fd5b506102b76108b53660046137a1565b61215c565b6108c26121d5565b816108cc81612222565b600083815260086020526040902060028101546108e890612277565b156109325760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093b846122eb565b610945818461238e565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b257506001600160e01b03198216635b5e139f60e01b145b806109cd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109de8261244d565b6000828152600860205260409020600201546109cd90612277565b606060008054610a0890613adc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3490613adc565b8015610a815780601f10610a5657610100808354040283529160200191610a81565b820191906000526020600020905b815481529060010190602001808311610a6457829003601f168201915b5050505050905090565b6000610a968261244d565b506000908152600460205260409020546001600160a01b031690565b6000610abd8261116c565b9050806001600160a01b0316836001600160a01b031603610b2a5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610929565b336001600160a01b0382161480610b465750610b468133610824565b610bb85760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610929565b610bc283836124ac565b505050565b610bcf6121d5565b81610bd981612222565b6000838152600860205260409020610bf1908361251a565b6040516001600160a01b038316815283907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a2505050565b610c3c6121d5565b81610c4681612222565b6000838152600860205260409020610c5d81612618565b610c678184612662565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c9991815260200190565b60405180910390a250505050565b610cb1338261274f565b610ccd5760405162461bcd60e51b815260040161092990613b16565b610bc28383836127cd565b610ce06121d5565b80610cea81612222565b6000828152600860205260409020610d0181612618565b610d0a8161293e565b15610d4e5760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b610d57816129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d8f612a1a565b610d97612a74565b565b6060816001600160401b03811115610db357610db36138df565b604051908082528060200260200182016040528015610de657816020015b6060815260200190600190039081610dd15790505b5090506000610df4600b5490565b905060005b83811015610f1357816001600160401b03811115610e1957610e196138df565b604051908082528060200260200182016040528015610e42578160200160208202803683370190505b50838281518110610e5557610e55613b63565b60200260200101819052506000600a6000878785818110610e7857610e78613b63565b9050602002016020810190610e8d91906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b83811015610f09576000818152602083905260409020548551869085908110610edd57610edd613b63565b60200260200101518281518110610ef657610ef6613b63565b6020908102919091010152600101610eb2565b5050600101610df9565b505092915050565b610bc283838360405180602001604052806000815250611863565b6000806000806000610f478661244d565b60008681526008602052604081208054600b80549293929091908110610f6f57610f6f613b63565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a509198509296506001600160a01b031694509092505050565b6000610fc6610fc18484612ac9565b612b30565b9392505050565b610fd56121d5565b60008060005b8481101561106c57858582818110610ff557610ff5613b63565b90506020020135925061100783612222565b6000838152600860205260409020915061102082612618565b61102a8285612662565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b8560405161105c91815260200190565b60405180910390a2600101610fdb565b505050505050565b61107c6121d5565b60008060005b838110156111035784848281811061109c5761109c613b63565b9050602002013592506110ae83612222565b600083815260086020526040902091506110c782612b61565b6110d082612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2600101611082565b5050505050565b6111126121d5565b8061111c81612222565b600082815260086020526040902061113381612b61565b61113c81612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cd5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b60006001600160a01b0382166112365760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610929565b506001600160a01b031660009081526003602052604090205490565b600061125c6121d5565b6000821180156112745750346112728387613b8f565b145b6112905760405162461bcd60e51b815260040161092990613ba6565b600061129c8686612ac9565b90506112a781612bff565b600754600101915060005b83811015611320576112c48286612c4b565b6112ce8184613bd2565b604080516001600160a01b0388168152602081018a90529081018890527f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a26001016112b2565b50505b949350505050565b611333612a1a565b610d976000612ce5565b606060008211801561135a5750600b546113578385613bd2565b11155b6113765760405162461bcd60e51b815260040161092990613ba6565b816001600160401b0381111561138e5761138e6138df565b6040519080825280602002602001820160405280156113e357816020015b6113d060405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816113ac5790505b50905060005b8281101561146b57600b8185018154811061140657611406613b63565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061144f5761144f613b63565b60200260200101819052506114648160010190565b90506113e9565b5092915050565b600061147c6121d5565b3460006114898286612ac9565b905061149481612bff565b61149e8185612c4b565b600754604080516001600160a01b03871681526020810185905290810187905281907f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a295945050505050565b6114fe612a1a565b610d97612d37565b60006115118261244d565b600082815260086020526040902061152881612618565b610fc68161293e565b606060018054610a0890613adc565b6060816001600160401b0381111561155a5761155a6138df565b60405190808252806020026020018201604052801561158d57816020015b60608152602001906001900390816115785790505b509050600061159b600b5490565b905060005b83811015610f1357816001600160401b038111156115c0576115c06138df565b6040519080825280602002602001820160405280156115e9578160200160208202803683370190505b508382815181106115fc576115fc613b63565b602002602001018190525060006009600087878581811061161f5761161f613b63565b905060200201602081019061163491906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b838110156116b057600081815260208390526040902054855186908590811061168457611684613b63565b6020026020010151828151811061169d5761169d613b63565b6020908102919091010152600101611659565b50506001016115a0565b6116c26121d5565b6000805b83811015611103578484828181106116e0576116e0613b63565b9050602002013591506116f282612222565b600082815260086020526040902061170a908461251a565b6040516001600160a01b038416815282907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a26001016116c6565b61175b338383612d7a565b5050565b6117676121d5565b8161177181612222565b600083815260086020526040902061178881612b61565b8054600b805460009190839081106117a2576117a2613b63565b90600052602060002090600302019050848160000154346117c39190613bd2565b146117e05760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a602090815260408083208584529091529020805460001901905560018101546118219084908790612e48565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161185391815260200190565b60405180910390a2505050505050565b61186d338361274f565b6118895760405162461bcd60e51b815260040161092990613b16565b61189584848484612e94565b50505050565b6118a36121d5565b60008060005b8481101561106c578585828181106118c3576118c3613b63565b9050602002013592506118d583612222565b600083815260086020526040902060028101549092506118f490612277565b156119395760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b6044820152606401610929565b611942836122eb565b61194c828561238e565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016118a9565b6119926121d5565b600182116119d35760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610929565b3460008080855b8015611b8a57600019018787828181106119f6576119f6613b63565b905060200201359350611a0884612222565b60008481526008602052604090209250611a2183612618565b82546003840154600b80546001600160a01b039092169183908110611a4857611a48613b63565b906000526020600020906003020193508360010154881015611a9f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b8354611aab9088613bd2565b9650611abd8560010154600019141590565b15611af2576001600160a01b038116600090815260096020908152604080832085845290915290208054600019019055611b1e565b6001600160a01b0381166000908152600a60209081526040808320858452909152902080546000190190555b8215611b3257611b2d866122eb565b611b83565b6000196001860155611b4585888a612e48565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611b7a9493929190613c10565b60405180910390a15b50506119da565b5050505050505050565b6060611b9f8261244d565b6000611bb660408051602081019091526000815290565b90506000815111611bd65760405180602001604052806000815250610fc6565b80611be084612ec7565b604051602001611bf1929190613c56565b6040516020818303038152906040529392505050565b611c0f612a1a565b81600003611c535760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b6044820152606401610929565b6000828152600c6020908152604080832084845290915290205415611cb25760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b6044820152606401610929565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b611db46121d5565b81611dbe81612222565b6000838152600860205260409020611dd581612b61565b8054600b80546000919083908110611def57611def613b63565b9060005260206000209060030201905080600101548511611e225760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a60209081526040808320858452909152902080546000190190558054611e5f90849087612e48565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161185391815260200190565b611e99612a1a565b43600b611ea68484612ac9565b81548110611eb657611eb6613b63565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611da0929190918252602082015260400190565b611f0d6121d5565b60008060005b8381101561110357848482818110611f2d57611f2d613b63565b905060200201359250611f3f83612222565b60008381526008602052604090209150611f5882612618565b611f618261293e565b15611fa55760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b611fae826129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611f13565b611fe9612a1a565b600019600b611ff88484612ac9565b8154811061200857612008613b63565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611da0929190918252602082015260400190565b60006120616121d5565b3482518561206f9190613b8f565b1461208c5760405162461bcd60e51b815260040161092990613ba6565b60006120988585612ac9565b90506120a381612bff565b600754600101915060005b8351811015612153576120da828583815181106120cd576120cd613b63565b6020026020010151612c4b565b6120e48184613bd2565b7f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a3285838151811061211757612117613b63565b602090810291909101810151604080516001600160a01b0390921682529181018a905290810188905260600160405180910390a26001016120ae565b50509392505050565b612164612a1a565b6001600160a01b0381166121c95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610929565b6121d281612ce5565b50565b600654600160a01b900460ff1615610d975760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610929565b61222b8161116c565b6001600160a01b0316336001600160a01b0316146121d25760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606401610929565b600060001982036122c35760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b6044820152606401610929565b60006122d0600a84613bd2565b90504381116122e25750600092915050565b43900392915050565b60006122f68261116c565b9050612306816000846001612f59565b61230f8261116c565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b8360000154815481106123a7576123a7613b63565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d8060008114612402576040519150601f19603f3d011682016040523d82523d6000602084013e612407565b606091505b50509050806118955760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b6044820152606401610929565b6000818152600260205260409020546001600160a01b03166121d25760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124e18261116c565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b61252382612618565b815460038301546001600160a01b0390811690831681036125565760405162461bcd60e51b815260040161092990613be5565b6001840154600019146125ac576001600160a01b038181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556125f1565b6001600160a01b038181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546001600160a01b0319166001600160a01b03909216919091179055565b6002810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b6044820152606401610929565b815460038301546001600160a01b031661267b8461293e565b8310156126bd5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b60006126ed600b84815481106126d5576126d5613b63565b90600052602060002090600302016000015485612ac9565b90506126f881612bff565b60001960018681018290556001600160a01b039390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061275b8361116c565b9050806001600160a01b0316846001600160a01b031614806127a257506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806113235750836001600160a01b03166127bb84610a8b565b6001600160a01b031614949350505050565b826001600160a01b03166127e08261116c565b6001600160a01b0316146128065760405162461bcd60e51b815260040161092990613c85565b6001600160a01b0382166128685760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610929565b6128758383836001612f59565b826001600160a01b03166128888261116c565b6001600160a01b0316146128ae5760405162461bcd60e51b815260040161092990613c85565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600181015460009060001981036129905760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b6044820152606401610929565b6000600b8460000154815481106129a9576129a9613b63565b906000526020600020906003020160010154826129c69190613bd2565b90504381116129d9575060009392505050565b4390039392505050565b43600282015560038101546001600160a01b0316600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d975760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610929565b612a7c613029565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b265760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b6044820152606401610929565b6000198101611323565b600043600b8381548110612b4657612b46613b63565b90600052602060002090600302016002015411159050919050565b6001810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b6044820152606401610929565b80546003820154436001938401556001600160a01b03166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b612c0881612b30565b6121d25760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b6044820152606401610929565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0389811660608601818152600098895260088552878920965187559251868a0155935160028601559051600390940180546001600160a01b03191694909116939093179092558352600a815281832087845290529020805490910190555461175b903390613079565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d3f6121d5565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612aac3390565b816001600160a01b0316836001600160a01b031603612ddb5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610929565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e548383612ac9565b9050612e5f81612bff565b60038401546001600160a01b03166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e9f8484846127cd565b612eab84848484613093565b6118955760405162461bcd60e51b815260040161092990613cca565b60606000612ed483613191565b60010190506000816001600160401b03811115612ef357612ef36138df565b6040519080825280601f01601f191660200182016040528015612f1d576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f2757509392505050565b80600114612fa95760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f72746564006044820152606401610929565b6001600160a01b0383161580612fd15750600082815260086020526040902060020154600019145b61301d5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e00006044820152606401610929565b61189584848484613269565b600654600160a01b900460ff16610d975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610929565b61175b8282604051806020016040528060008152506132f1565b60006001600160a01b0384163b1561318957604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130d7903390899088908890600401613d1c565b6020604051808303816000875af1925050508015613112575060408051601f3d908101601f1916820190925261310f91810190613d59565b60015b61316f573d808015613140576040519150601f19603f3d011682016040523d82523d6000602084013e613145565b606091505b5080516000036131675760405162461bcd60e51b815260040161092990613cca565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611323565b506001611323565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131d05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131fc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061321a57662386f26fc10000830492506010015b6305f5e1008310613232576305f5e100830492506008015b612710831061324657612710830492506004015b60648310613258576064830492506002015b600a83106109cd5760010192915050565b6001811115611895576001600160a01b038416156132af576001600160a01b038416600090815260036020526040812080548392906132a9908490613d76565b90915550505b6001600160a01b03831615611895576001600160a01b038316600090815260036020526040812080548392906132e6908490613bd2565b909155505050505050565b6132fb8383613324565b6133086000848484613093565b610bc25760405162461bcd60e51b815260040161092990613cca565b6001600160a01b03821661337a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610929565b6000818152600260205260409020546001600160a01b0316156133df5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6133ed600083836001612f59565b6000818152600260205260409020546001600160a01b0316156134525760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121d257600080fd5b600080604083850312156134e557600080fd5b8235915060208301356134f7816134bd565b809150509250929050565b6001600160e01b0319811681146121d257600080fd5b60006020828403121561352a57600080fd5b8135610fc681613502565b60006020828403121561354757600080fd5b5035919050565b60005b83811015613569578181015183820152602001613551565b50506000910152565b6000815180845261358a81602086016020860161354e565b601f01601f19169290920160200192915050565b602081526000610fc66020830184613572565b600080604083850312156135c457600080fd5b82356135cf816134bd565b946020939093013593505050565b600080604083850312156135f057600080fd5b50508035926020909101359150565b60008060006060848603121561361457600080fd5b833561361f816134bd565b9250602084013561362f816134bd565b929592945050506040919091013590565b60008083601f84011261365257600080fd5b5081356001600160401b0381111561366957600080fd5b6020830191508360208260051b850101111561368457600080fd5b9250929050565b6000806020838503121561369e57600080fd5b82356001600160401b038111156136b457600080fd5b6136c085828601613640565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b8381101561374857888603603f19018552825180518088529088019088880190845b818110156137325783518352928a0192918a0191600101613716565b50909750505093860193918601916001016136f4565b509398975050505050505050565b60008060006040848603121561376b57600080fd5b83356001600160401b0381111561378157600080fd5b61378d86828701613640565b909790965060209590950135949350505050565b6000602082840312156137b357600080fd5b8135610fc6816134bd565b600080600080608085870312156137d457600080fd5b843593506020850135925060408501356137ed816134bd565b9396929550929360600135925050565b602080825282518282018190526000919060409081850190868401855b82811015613849578151805185528681015187860152850151858501526060909301929085019060010161381a565b5091979650505050505050565b60008060006040848603121561386b57600080fd5b83356001600160401b0381111561388157600080fd5b61388d86828701613640565b90945092505060208401356138a1816134bd565b809150509250925092565b600080604083850312156138bf57600080fd5b82356138ca816134bd565b9150602083013580151581146134f757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561391d5761391d6138df565b604052919050565b6000806000806080858703121561393b57600080fd5b8435613946816134bd565b9350602085810135613957816134bd565b93506040860135925060608601356001600160401b038082111561397a57600080fd5b818801915088601f83011261398e57600080fd5b8135818111156139a0576139a06138df565b6139b2601f8201601f191685016138f5565b915080825289848285010111156139c857600080fd5b808484018584013760008482840101525080935050505092959194509250565b600080604083850312156139fb57600080fd5b8235613a06816134bd565b915060208301356134f7816134bd565b600080600060608486031215613a2b57600080fd5b83359250602080850135925060408501356001600160401b0380821115613a5157600080fd5b818701915087601f830112613a6557600080fd5b813581811115613a7757613a776138df565b8060051b9150613a888483016138f5565b818152918301840191848101908a841115613aa257600080fd5b938501935b83851015613acc5784359250613abc836134bd565b8282529385019390850190613aa7565b8096505050505050509250925092565b600181811c90821680613af057607f821691505b602082108103613b1057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176109cd576109cd613b79565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b808201808211156109cd576109cd613b79565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3057600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6881846020880161354e565b835190830190613c7c81836020880161354e565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d4f90830184613572565b9695505050505050565b600060208284031215613d6b57600080fd5b8151610fc681613502565b818103818111156109cd576109cd613b7956fea2646970667358221220be917767ef1b31d340fe6087913ba2e72285104d0b6c49192dabe393bb91652864736f6c63430008120033` _liquidStakingContractABI = `[ { "inputs": [], @@ -164,9 +162,9 @@ const ( }, { "indexed": false, - "internalType": "bytes12", + "internalType": "address", "name": "newDelegate", - "type": "bytes12" + "type": "address" } ], "name": "DelegateChanged", @@ -278,9 +276,9 @@ const ( }, { "indexed": false, - "internalType": "bytes12", + "internalType": "address", "name": "delegate", - "type": "bytes12" + "type": "address" }, { "indexed": false, @@ -549,9 +547,9 @@ const ( "type": "uint256" }, { - "internalType": "bytes12", + "internalType": "address", "name": "delegate_", - "type": "bytes12" + "type": "address" } ], "stateMutability": "view", @@ -606,9 +604,9 @@ const ( "type": "uint256" }, { - "internalType": "bytes12", + "internalType": "address", "name": "_delegate", - "type": "bytes12" + "type": "address" } ], "name": "changeDelegate", @@ -624,9 +622,9 @@ const ( "type": "uint256[]" }, { - "internalType": "bytes12", + "internalType": "address", "name": "_delegate", - "type": "bytes12" + "type": "address" } ], "name": "changeDelegates", @@ -794,9 +792,9 @@ const ( { "inputs": [ { - "internalType": "bytes12[]", + "internalType": "address[]", "name": "_delegates", - "type": "bytes12[]" + "type": "address[]" } ], "name": "lockedVotesTo", @@ -984,22 +982,32 @@ const ( }, { "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, { "internalType": "uint256", "name": "_duration", "type": "uint256" }, { - "internalType": "bytes12", + "internalType": "address", "name": "_delegate", - "type": "bytes12" + "type": "address" + }, + { + "internalType": "uint256", + "name": "_count", + "type": "uint256" } ], "name": "stake", "outputs": [ { "internalType": "uint256", - "name": "", + "name": "firstTokenId_", "type": "uint256" } ], @@ -1008,32 +1016,22 @@ const ( }, { "inputs": [ - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - }, { "internalType": "uint256", "name": "_duration", "type": "uint256" }, { - "internalType": "bytes12", + "internalType": "address", "name": "_delegate", - "type": "bytes12" - }, - { - "internalType": "uint256", - "name": "_count", - "type": "uint256" + "type": "address" } ], "name": "stake", "outputs": [ { "internalType": "uint256", - "name": "firstTokenId_", + "name": "", "type": "uint256" } ], @@ -1053,9 +1051,9 @@ const ( "type": "uint256" }, { - "internalType": "bytes12[]", + "internalType": "address[]", "name": "_delegates", - "type": "bytes12[]" + "type": "address[]" } ], "name": "stake", @@ -1185,9 +1183,9 @@ const ( { "inputs": [ { - "internalType": "bytes12[]", + "internalType": "address[]", "name": "_delegates", - "type": "bytes12[]" + "type": "address[]" } ], "name": "unlockedVotesTo", @@ -1276,14 +1274,14 @@ const ( ) var ( - _delegates = []string{ - "delegate0", - "delegate1", - "delegate2", - "delegate3", - "delegate4", - "delegate5", - "delegate6", + _delegates = []common.Address{ + common.BytesToAddress(identityset.Address(0).Bytes()), + common.BytesToAddress(identityset.Address(1).Bytes()), + common.BytesToAddress(identityset.Address(2).Bytes()), + common.BytesToAddress(identityset.Address(3).Bytes()), + common.BytesToAddress(identityset.Address(4).Bytes()), + common.BytesToAddress(identityset.Address(5).Bytes()), + common.BytesToAddress(identityset.Address(6).Bytes()), } ) @@ -1348,15 +1346,14 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipt.Status) } - simpleStake := func(candName string, amount, duration *big.Int) *blockindex.Bucket { - return stake(lsdABI, bc, sf, dao, ap, contractAddresses, indexer, r, candName, amount, duration) + simpleStake := func(cand common.Address, amount, duration *big.Int) *blockindex.Bucket { + return stake(lsdABI, bc, sf, dao, ap, contractAddresses, indexer, r, cand, amount, duration) } t.Run("stake", func(t *testing.T) { delegateIdx := 2 - delegate := [12]byte{} - copy(delegate[:], []byte(_delegates[delegateIdx])) - data, err := lsdABI.Pack("stake", big.NewInt(10), delegate) + delegate := _delegates[delegateIdx] + data, err := lsdABI.Pack("stake0", big.NewInt(10), delegate) r.NoError(err) param := callParam{ contractAddr: contractAddresses, @@ -1385,7 +1382,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) r.True(bt.UnstakeStartTime.IsZero()) - r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) t.Run("unlock", func(t *testing.T) { @@ -1406,7 +1403,7 @@ func TestLiquidStaking(t *testing.T) { bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) - r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) t.Run("unstake", func(t *testing.T) { @@ -1428,7 +1425,7 @@ func TestLiquidStaking(t *testing.T) { bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) r.EqualValues(blk.Timestamp().UTC().Unix(), bt.UnstakeStartTime.Unix()) - r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx).String()).Int64()) + r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) t.Run("withdraw", func(t *testing.T) { @@ -1460,7 +1457,7 @@ func TestLiquidStaking(t *testing.T) { }) t.Run("lock & unlock", func(t *testing.T) { - bt := simpleStake("delegate3", big.NewInt(10), big.NewInt(10)) + bt := simpleStake(_delegates[3], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index data, err := lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) @@ -1503,7 +1500,7 @@ func TestLiquidStaking(t *testing.T) { for i := 0; i < 10; i++ { delegate := [12]byte{} copy(delegate[:], []byte(candName)) - data, err := lsdABI.Pack("stake", big.NewInt(10), delegate) + data, err := lsdABI.Pack("stake0", big.NewInt(10), delegate) r.NoError(err) param := callParam{ contractAddr: contractAddresses, @@ -1560,7 +1557,7 @@ func TestLiquidStaking(t *testing.T) { t.Run("extend duration", func(t *testing.T) { // stake - bt := simpleStake("delegate3", big.NewInt(10), big.NewInt(10)) + bt := simpleStake(_delegates[3], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) // extend duration @@ -1583,7 +1580,7 @@ func TestLiquidStaking(t *testing.T) { }) t.Run("increase amount", func(t *testing.T) { - bt := simpleStake("delegate4", big.NewInt(10), big.NewInt(10)) + bt := simpleStake(_delegates[4], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index data, err := lsdABI.Pack("increaseAmount", big.NewInt(int64(tokenID)), big.NewInt(100)) @@ -1612,8 +1609,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(identityset.Address(delegateIdx).String(), bt.Candidate.String()) delegateIdx = 6 - delegate := [12]byte{} - copy(delegate[:], []byte(_delegates[delegateIdx])) + delegate := _delegates[delegateIdx] data, err := lsdABI.Pack("changeDelegate", big.NewInt(int64(tokenID)), delegate) r.NoError(err) param = callParam{ @@ -1703,14 +1699,7 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r r.NoError(err) cc := cfg.DB cc.DbPath = testLiquidStakeIndexerPath - candNameToOwner := func(name string) (address.Address, error) { - idx := slices.Index(_delegates, name) - if idx == -1 { - return &address.AddrV1{}, errors.New("delegate not found") - } - return identityset.Address(idx), nil - } - liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval, candNameToOwner) + liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) // create BlockDAO dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) r.NotNil(dao) @@ -1855,10 +1844,9 @@ func jumpBlocks(bc blockchain.Blockchain, count int, r *require.Assertions) { } } -func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blockdao.BlockDAO, ap actpool.ActPool, contractAddresses string, indexer blockindex.LiquidStakingIndexer, r *require.Assertions, candName string, amount, duration *big.Int) *blockindex.Bucket { - delegate := [12]byte{} - copy(delegate[:], []byte(candName)) - data, err := lsdABI.Pack("stake", duration, delegate) +func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blockdao.BlockDAO, ap actpool.ActPool, contractAddresses string, indexer blockindex.LiquidStakingIndexer, r *require.Assertions, cand common.Address, amount, duration *big.Int) *blockindex.Bucket { + delegate := cand + data, err := lsdABI.Pack("stake0", duration, delegate) r.NoError(err) param := callParam{ contractAddr: contractAddresses, From 95dee452d3c588da1853a5098988081b9fcbe6d7 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 16 May 2023 22:37:07 +0800 Subject: [PATCH 38/51] change duration and time to block number --- blockindex/indexpb/liquidstaking_bucket.pb.go | 109 ++++++++---------- blockindex/indexpb/liquidstaking_bucket.proto | 9 +- blockindex/liquidstaking_bucket.go | 69 ++++++----- blockindex/liquidstaking_cache.go | 25 ++-- blockindex/liquidstaking_cache_test.go | 5 +- blockindex/liquidstaking_dirty.go | 3 +- blockindex/liquidstaking_indexer.go | 59 +++++----- e2etest/liquid_staking_test.go | 19 +-- 8 files changed, 140 insertions(+), 158 deletions(-) diff --git a/blockindex/indexpb/liquidstaking_bucket.pb.go b/blockindex/indexpb/liquidstaking_bucket.pb.go index f029e70767..1bb3d5b164 100644 --- a/blockindex/indexpb/liquidstaking_bucket.pb.go +++ b/blockindex/indexpb/liquidstaking_bucket.pb.go @@ -17,7 +17,6 @@ package indexpb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -34,9 +33,9 @@ type BucketType struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` - Duration uint64 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"` - ActivatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=activatedAt,proto3" json:"activatedAt,omitempty"` + Amount string `protobuf:"bytes,1,opt,name=amount,proto3" json:"amount,omitempty"` + Duration uint64 `protobuf:"varint,2,opt,name=duration,proto3" json:"duration,omitempty"` + ActivatedAt uint64 `protobuf:"varint,3,opt,name=activatedAt,proto3" json:"activatedAt,omitempty"` } func (x *BucketType) Reset() { @@ -85,11 +84,11 @@ func (x *BucketType) GetDuration() uint64 { return 0 } -func (x *BucketType) GetActivatedAt() *timestamppb.Timestamp { +func (x *BucketType) GetActivatedAt() uint64 { if x != nil { return x.ActivatedAt } - return nil + return 0 } type BucketInfo struct { @@ -97,12 +96,12 @@ type BucketInfo struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - TypeIndex uint64 `protobuf:"varint,1,opt,name=typeIndex,proto3" json:"typeIndex,omitempty"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=createdAt,proto3" json:"createdAt,omitempty"` - UnlockedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` - UnstakedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` - Delegate string `protobuf:"bytes,5,opt,name=delegate,proto3" json:"delegate,omitempty"` - Owner string `protobuf:"bytes,6,opt,name=owner,proto3" json:"owner,omitempty"` + TypeIndex uint64 `protobuf:"varint,1,opt,name=typeIndex,proto3" json:"typeIndex,omitempty"` + CreatedAt uint64 `protobuf:"varint,2,opt,name=createdAt,proto3" json:"createdAt,omitempty"` + UnlockedAt uint64 `protobuf:"varint,3,opt,name=unlockedAt,proto3" json:"unlockedAt,omitempty"` + UnstakedAt uint64 `protobuf:"varint,4,opt,name=unstakedAt,proto3" json:"unstakedAt,omitempty"` + Delegate string `protobuf:"bytes,5,opt,name=delegate,proto3" json:"delegate,omitempty"` + Owner string `protobuf:"bytes,6,opt,name=owner,proto3" json:"owner,omitempty"` } func (x *BucketInfo) Reset() { @@ -144,25 +143,25 @@ func (x *BucketInfo) GetTypeIndex() uint64 { return 0 } -func (x *BucketInfo) GetCreatedAt() *timestamppb.Timestamp { +func (x *BucketInfo) GetCreatedAt() uint64 { if x != nil { return x.CreatedAt } - return nil + return 0 } -func (x *BucketInfo) GetUnlockedAt() *timestamppb.Timestamp { +func (x *BucketInfo) GetUnlockedAt() uint64 { if x != nil { return x.UnlockedAt } - return nil + return 0 } -func (x *BucketInfo) GetUnstakedAt() *timestamppb.Timestamp { +func (x *BucketInfo) GetUnstakedAt() uint64 { if x != nil { return x.UnstakedAt } - return nil + return 0 } func (x *BucketInfo) GetDelegate() string { @@ -185,38 +184,29 @@ var file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = []byte{ 0x0a, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x2f, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x73, 0x74, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7e, 0x0a, 0x0a, 0x42, 0x75, 0x63, - 0x6b, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0b, 0x61, - 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x8e, 0x02, 0x0a, 0x0a, 0x42, 0x75, - 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x79, 0x70, - 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x38, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, - 0x12, 0x3a, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3a, 0x0a, 0x0a, - 0x75, 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, 0x6e, - 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, - 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x22, 0x62, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xba, 0x01, 0x0a, + 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x74, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, + 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x6c, + 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, + 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x73, + 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -233,20 +223,15 @@ func file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP() []byte { var file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = []interface{}{ - (*BucketType)(nil), // 0: indexpb.BucketType - (*BucketInfo)(nil), // 1: indexpb.BucketInfo - (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp + (*BucketType)(nil), // 0: indexpb.BucketType + (*BucketInfo)(nil), // 1: indexpb.BucketInfo } var file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = []int32{ - 2, // 0: indexpb.BucketType.activatedAt:type_name -> google.protobuf.Timestamp - 2, // 1: indexpb.BucketInfo.createdAt:type_name -> google.protobuf.Timestamp - 2, // 2: indexpb.BucketInfo.unlockedAt:type_name -> google.protobuf.Timestamp - 2, // 3: indexpb.BucketInfo.unstakedAt:type_name -> google.protobuf.Timestamp - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_blockindex_indexpb_liquidstaking_bucket_proto_init() } diff --git a/blockindex/indexpb/liquidstaking_bucket.proto b/blockindex/indexpb/liquidstaking_bucket.proto index 47e580aa33..2a5a94f7cd 100644 --- a/blockindex/indexpb/liquidstaking_bucket.proto +++ b/blockindex/indexpb/liquidstaking_bucket.proto @@ -8,19 +8,18 @@ syntax = "proto3"; package indexpb; option go_package = "github.com/iotexproject/iotex-core/blockindex/indexpb"; -import "google/protobuf/timestamp.proto"; message BucketType { string amount = 1; uint64 duration = 2; - google.protobuf.Timestamp activatedAt = 3; + uint64 activatedAt = 3; } message BucketInfo { uint64 typeIndex = 1; - google.protobuf.Timestamp createdAt = 2; - google.protobuf.Timestamp unlockedAt = 3; - google.protobuf.Timestamp unstakedAt = 4; + uint64 createdAt = 2; + uint64 unlockedAt = 3; + uint64 unstakedAt = 4; string delegate = 5; string owner = 6; } diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index b22726599b..5a63512e06 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -6,27 +6,29 @@ package blockindex import ( + "math" "math/big" - "time" "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/timestamppb" "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-core/action/protocol/staking" "github.com/iotexproject/iotex-core/blockindex/indexpb" "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) +const ( + maxBlockNumber = math.MaxUint64 +) + type ( // BucketInfo is the bucket information BucketInfo struct { TypeIndex uint64 - CreatedAt time.Time - UnlockedAt time.Time - UnstakedAt time.Time + CreatedAt uint64 + UnlockedAt uint64 + UnstakedAt uint64 Delegate address.Address // owner address of the delegate Owner address.Address } @@ -34,19 +36,29 @@ type ( // BucketType is the bucket type BucketType struct { Amount *big.Int - Duration time.Duration - ActivatedAt time.Time + Duration uint64 + ActivatedAt uint64 } // Bucket is the bucket information including bucket type and bucket info - Bucket = staking.VoteBucket + Bucket struct { + Index uint64 + Candidate address.Address + Owner address.Address + StakedAmount *big.Int + StakedDuration uint64 + CreateTime uint64 + StakeStartTime uint64 + UnstakeStartTime uint64 + AutoStake bool + } ) func (bt *BucketType) toProto() *indexpb.BucketType { return &indexpb.BucketType{ Amount: bt.Amount.String(), - Duration: uint64(bt.Duration), - ActivatedAt: timestamppb.New(bt.ActivatedAt), + Duration: bt.Duration, + ActivatedAt: bt.ActivatedAt, } } @@ -56,8 +68,8 @@ func (bt *BucketType) loadProto(p *indexpb.BucketType) error { if !ok { return errors.New("failed to parse amount") } - bt.Duration = time.Duration(p.Duration) - bt.ActivatedAt = p.ActivatedAt.AsTime() + bt.Duration = p.Duration + bt.ActivatedAt = p.ActivatedAt return nil } @@ -75,17 +87,12 @@ func (bt *BucketType) deserialize(b []byte) error { func (bi *BucketInfo) toProto() *indexpb.BucketInfo { pb := &indexpb.BucketInfo{ - TypeIndex: bi.TypeIndex, - Delegate: bi.Delegate.String(), - CreatedAt: timestamppb.New(bi.CreatedAt), - Owner: bi.Owner.String(), - } - if !bi.UnlockedAt.IsZero() { - pb.UnlockedAt = timestamppb.New(bi.UnlockedAt) - } - time.Unix(0, 0).UTC() - if !bi.UnstakedAt.IsZero() { - pb.UnstakedAt = timestamppb.New(bi.UnstakedAt) + TypeIndex: bi.TypeIndex, + Delegate: bi.Delegate.String(), + CreatedAt: bi.CreatedAt, + Owner: bi.Owner.String(), + UnlockedAt: bi.UnlockedAt, + UnstakedAt: bi.UnstakedAt, } return pb } @@ -105,17 +112,9 @@ func (bi *BucketInfo) deserialize(b []byte) error { func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { var err error bi.TypeIndex = p.TypeIndex - bi.CreatedAt = p.CreatedAt.AsTime() - if p.UnlockedAt != nil { - bi.UnlockedAt = p.UnlockedAt.AsTime() - } else { - bi.UnlockedAt = time.Time{} - } - if p.UnstakedAt != nil { - bi.UnstakedAt = p.UnstakedAt.AsTime() - } else { - bi.UnstakedAt = time.Time{} - } + bi.CreatedAt = p.CreatedAt + bi.UnlockedAt = p.UnlockedAt + bi.UnstakedAt = p.UnstakedAt bi.Delegate, err = address.FromString(p.Delegate) if err != nil { return err diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 8619635ea1..b83eb79687 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -8,7 +8,6 @@ package blockindex import ( "math/big" "sync" - "time" "github.com/iotexproject/iotex-address/address" ) @@ -20,7 +19,7 @@ type ( getHeight() uint64 getTotalBucketCount() uint64 getTotalBucketTypeCount() uint64 - getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) + getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) getBucketType(id uint64) (*BucketType, bool) getBucketInfo(id uint64) (*BucketInfo, bool) mustGetBucketType(id uint64) *BucketType @@ -42,10 +41,10 @@ type ( } liquidStakingCache struct { - idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo - candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket - idBucketTypeMap map[uint64]*BucketType // map[token]BucketType - propertyBucketTypeMap map[int64]map[int64]uint64 // map[amount][duration]index + idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo + candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket + idBucketTypeMap map[uint64]*BucketType // map[token]BucketType + propertyBucketTypeMap map[int64]map[uint64]uint64 // map[amount][duration]index height uint64 totalBucketCount uint64 // total number of buckets including burned buckets } @@ -60,7 +59,7 @@ func newLiquidStakingCache() *liquidStakingCacheThreadSafety { cache := &liquidStakingCache{ idBucketMap: make(map[uint64]*BucketInfo), idBucketTypeMap: make(map[uint64]*BucketType), - propertyBucketTypeMap: make(map[int64]map[int64]uint64), + propertyBucketTypeMap: make(map[int64]map[uint64]uint64), candidateBucketMap: make(map[string]map[uint64]bool), } return &liquidStakingCacheThreadSafety{cache: cache} @@ -79,10 +78,10 @@ func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { s.idBucketTypeMap[id] = bt m, ok := s.propertyBucketTypeMap[amount] if !ok { - s.propertyBucketTypeMap[amount] = make(map[int64]uint64) + s.propertyBucketTypeMap[amount] = make(map[uint64]uint64) m = s.propertyBucketTypeMap[amount] } - m[int64(bt.Duration)] = id + m[bt.Duration] = id } func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { @@ -105,12 +104,12 @@ func (s *liquidStakingCache) deleteBucketInfo(id uint64) { delete(s.candidateBucketMap[bi.Delegate.String()], id) } -func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { +func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { m, ok := s.propertyBucketTypeMap[amount.Int64()] if !ok { return 0, false } - id, ok := m[int64(duration)] + id, ok := m[duration] return id, ok } @@ -154,7 +153,7 @@ func (s *liquidStakingCache) getCandidateVotes(candidate address.Address) *big.I if !ok { continue } - if !bi.UnstakedAt.IsZero() { + if bi.UnstakedAt != maxBlockNumber { continue } bt := s.mustGetBucketType(bi.TypeIndex) @@ -235,7 +234,7 @@ func (s *liquidStakingCacheThreadSafety) deleteBucketInfo(id uint64) { s.cache.deleteBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { +func (s *liquidStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { s.mutex.RLock() defer s.mutex.RUnlock() diff --git a/blockindex/liquidstaking_cache_test.go b/blockindex/liquidstaking_cache_test.go index e745ee709d..28445ea16f 100644 --- a/blockindex/liquidstaking_cache_test.go +++ b/blockindex/liquidstaking_cache_test.go @@ -9,7 +9,6 @@ import ( "math/big" "sync" "testing" - "time" ) func TestLiquidStakingCacheThreadSafety(t *testing.T) { @@ -21,8 +20,8 @@ func TestLiquidStakingCacheThreadSafety(t *testing.T) { for i := 0; i < 1000; i++ { cache.putBucketType(uint64(i), &BucketType{ Amount: big.NewInt(int64(i)), - Duration: time.Hour, - ActivatedAt: time.Now(), + Duration: 1000, + ActivatedAt: 10, }) } wait.Done() diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 955372eb9c..b2717c6fb8 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -8,7 +8,6 @@ package blockindex import ( "math/big" "sync" - "time" "github.com/iotexproject/iotex-address/address" @@ -70,7 +69,7 @@ func (s *liquidStakingDirty) burnBucket(id uint64) error { return s.delta.deleteBucketInfo(id) } -func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration time.Duration) (uint64, bool) { +func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { id, ok := s.delta.getBucketTypeIndex(amount, duration) if ok { return id, true diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 62d8c7f8bd..098c964894 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -567,20 +567,19 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidSta } // handle different kinds of event - timestamp := blk.Timestamp() switch abiEvent.Name { case "BucketTypeActivated": - return s.handleBucketTypeActivatedEvent(dirty, event, timestamp) + return s.handleBucketTypeActivatedEvent(dirty, event, blk.Height()) case "BucketTypeDeactivated": - return s.handleBucketTypeDeactivatedEvent(dirty, event) + return s.handleBucketTypeDeactivatedEvent(dirty, event, blk.Height()) case "Staked": - return s.handleStakedEvent(dirty, event, timestamp) + return s.handleStakedEvent(dirty, event, blk.Height()) case "Locked": return s.handleLockedEvent(dirty, event) case "Unlocked": - return s.handleUnlockedEvent(dirty, event, timestamp) + return s.handleUnlockedEvent(dirty, event, blk.Height()) case "Unstaked": - return s.handleUnstakedEvent(dirty, event, timestamp) + return s.handleUnstakedEvent(dirty, event, blk.Height()) case "Merged": return s.handleMergedEvent(dirty, event) case "DurationExtended": @@ -612,7 +611,7 @@ func (s *liquidStakingIndexer) handleTransferEvent(dirty *liquidStakingDirty, ev return nil } -func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStakingDirty, event eventParam, timeStamp time.Time) error { +func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -624,8 +623,8 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStaki bt := BucketType{ Amount: amountParam, - Duration: s.blockHeightToDuration(durationParam.Uint64()), - ActivatedAt: timeStamp, + Duration: durationParam.Uint64(), + ActivatedAt: height, } id, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) if !ok { @@ -638,7 +637,7 @@ func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStaki return err } -func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidStakingDirty, event eventParam) error { +func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -648,7 +647,7 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidSta return err } - id, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + id, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } @@ -656,11 +655,11 @@ func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidSta if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", id) } - bt.ActivatedAt = time.Time{} + bt.ActivatedAt = maxBlockNumber return dirty.updateBucketType(id, bt) } -func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -678,15 +677,17 @@ func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, even return err } - btIdx, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } bucket := BucketInfo{ - TypeIndex: btIdx, - Delegate: delegateParam, - Owner: dirty.tokenOwner[tokenIDParam.Uint64()], - CreatedAt: timestamp, + TypeIndex: btIdx, + Delegate: delegateParam, + Owner: dirty.tokenOwner[tokenIDParam.Uint64()], + CreatedAt: height, + UnlockedAt: maxBlockNumber, + UnstakedAt: maxBlockNumber, } return dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) } @@ -709,16 +710,16 @@ func (s *liquidStakingIndexer) handleLockedEvent(dirty *liquidStakingDirty, even if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) } b.TypeIndex = newBtIdx - b.UnlockedAt = time.Time{} + b.UnlockedAt = maxBlockNumber return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -728,11 +729,11 @@ func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, ev if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - b.UnlockedAt = timestamp + b.UnlockedAt = height return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, event eventParam, timestamp time.Time) error { +func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -742,7 +743,7 @@ func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, ev if !ok { return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) } - b.UnstakedAt = timestamp + b.UnstakedAt = height return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } @@ -761,7 +762,7 @@ func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, even } // merge to the first bucket - btIdx, ok := dirty.getBucketTypeIndex(amountParam, s.blockHeightToDuration(durationParam.Uint64())) + btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } @@ -770,7 +771,7 @@ func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, even return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) } b.TypeIndex = btIdx - b.UnlockedAt = time.Time{} + b.UnlockedAt = maxBlockNumber for i := 1; i < len(tokenIDsParam); i++ { if err = dirty.burnBucket(tokenIDsParam[i].Uint64()); err != nil { return err @@ -797,7 +798,7 @@ func (s *liquidStakingIndexer) handleDurationExtendedEvent(dirty *liquidStakingD if !ok { return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) } - newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, s.blockHeightToDuration(durationParam.Uint64())) + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) } @@ -941,11 +942,11 @@ func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, CreateTime: bi.CreatedAt, StakeStartTime: bi.CreatedAt, UnstakeStartTime: bi.UnstakedAt, - AutoStake: bi.UnlockedAt.IsZero(), + AutoStake: bi.UnlockedAt == maxBlockNumber, Candidate: bi.Delegate, Owner: bi.Owner, } - if !bi.UnlockedAt.IsZero() { + if bi.UnlockedAt != maxBlockNumber { vb.StakeStartTime = bi.UnlockedAt } return &vb, nil diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index bc71e34415..665ba6643c 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -3,6 +3,7 @@ package e2etest import ( "context" "encoding/hex" + "math" "math/big" "strings" "testing" @@ -1378,10 +1379,10 @@ func TestLiquidStaking(t *testing.T) { r.Equal(identityset.Address(delegateIdx).String(), bt.Candidate.String()) r.EqualValues(identityset.PrivateKey(adminID).PublicKey().Address().String(), bt.Owner.String()) r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) - r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) - r.EqualValues(blk.Timestamp().Unix(), bt.CreateTime.Unix()) - r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) - r.True(bt.UnstakeStartTime.IsZero()) + r.EqualValues(10, bt.StakedDuration) + r.EqualValues(blk.Height(), bt.CreateTime) + r.EqualValues(blk.Height(), bt.StakeStartTime) + r.True(bt.UnstakeStartTime == math.MaxUint64) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1402,7 +1403,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Timestamp().UTC().Unix(), bt.StakeStartTime.Unix()) + r.EqualValues(blk.Height(), bt.StakeStartTime) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1424,7 +1425,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Timestamp().UTC().Unix(), bt.UnstakeStartTime.Unix()) + r.EqualValues(blk.Height(), bt.UnstakeStartTime) r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1547,7 +1548,7 @@ func TestLiquidStaking(t *testing.T) { if i == 0 { bt, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.NoError(err) - r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) + r.EqualValues(100, bt.StakedDuration) } else { _, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) @@ -1559,7 +1560,7 @@ func TestLiquidStaking(t *testing.T) { // stake bt := simpleStake(_delegates[3], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index - r.EqualValues(10*cfg.Genesis.BlockInterval, bt.StakedDuration) + r.EqualValues(10, bt.StakedDuration) // extend duration data, err := lsdABI.Pack("extendDuration", big.NewInt(int64(tokenID)), big.NewInt(100)) r.NoError(err) @@ -1576,7 +1577,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(100*cfg.Genesis.BlockInterval, bt.StakedDuration) + r.EqualValues(100, bt.StakedDuration) }) t.Run("increase amount", func(t *testing.T) { From d7c6999772477c4640c8b5d4b6bc779261eb98a8 Mon Sep 17 00:00:00 2001 From: envestcc Date: Tue, 16 May 2023 23:00:13 +0800 Subject: [PATCH 39/51] add get bucket types --- blockindex/liquidstaking_cache.go | 18 ++++++++++++++++++ blockindex/liquidstaking_indexer.go | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index b83eb79687..0026b31b89 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -25,6 +25,7 @@ type ( mustGetBucketType(id uint64) *BucketType mustGetBucketInfo(id uint64) *BucketInfo getAllBucketInfo() map[uint64]*BucketInfo + getActiveBucketType() map[uint64]*BucketType getCandidateVotes(candidate address.Address) *big.Int } @@ -182,6 +183,16 @@ func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*BucketInfo { return m } +func (s *liquidStakingCache) getActiveBucketType() map[uint64]*BucketType { + m := make(map[uint64]*BucketType) + for k, v := range s.idBucketTypeMap { + if v.ActivatedAt != maxBlockNumber { + m[k] = v + } + } + return m +} + func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { for id, state := range delta.bucketTypeDeltaState { if state == deltaStateAdded || state == deltaStateModified { @@ -304,6 +315,13 @@ func (s *liquidStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*BucketIn return s.cache.getAllBucketInfo() } +func (s *liquidStakingCacheThreadSafety) getActiveBucketType() map[uint64]*BucketType { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getActiveBucketType() +} + func (s *liquidStakingCacheThreadSafety) merge(delta *liquidStakingDelta) error { s.mutex.Lock() defer s.mutex.Unlock() diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 098c964894..eeedeb1bc0 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -384,6 +384,7 @@ type ( Bucket(id uint64) (*Bucket, error) BucketsByIndices(indices []uint64) ([]*Bucket, error) TotalBucketCount() uint64 + ActiveBucketTypes() (map[uint64]*BucketType, error) } // liquidStakingIndexer is the implementation of LiquidStakingIndexer @@ -553,6 +554,10 @@ func (s *liquidStakingIndexer) TotalBucketCount() uint64 { return s.cache.getTotalBucketCount() } +func (s *liquidStakingIndexer) ActiveBucketTypes() (map[uint64]*BucketType, error) { + return s.cache.getActiveBucketType(), nil +} + func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) From 56f60bc4ab639274dd4ff35b6eab8879eafccd1d Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 17 May 2023 17:46:14 +0800 Subject: [PATCH 40/51] address comments --- blockindex/liquidstaking_bucket.go | 3 +- blockindex/liquidstaking_cache.go | 4 + blockindex/liquidstaking_dirty.go | 337 ++++++++++++++++++++++--- blockindex/liquidstaking_indexer.go | 364 +++------------------------- e2etest/liquid_staking_test.go | 2 +- 5 files changed, 342 insertions(+), 368 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index 5a63512e06..7ec676eff5 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -9,11 +9,10 @@ import ( "math" "math/big" + "github.com/iotexproject/iotex-address/address" "github.com/pkg/errors" "google.golang.org/protobuf/proto" - "github.com/iotexproject/iotex-address/address" - "github.com/iotexproject/iotex-core/blockindex/indexpb" "github.com/iotexproject/iotex-core/pkg/util/byteutil" ) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 0026b31b89..ab0c2d5f8f 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -328,3 +328,7 @@ func (s *liquidStakingCacheThreadSafety) merge(delta *liquidStakingDelta) error return s.cache.merge(delta) } + +func (s *liquidStakingCacheThreadSafety) unsafe() liquidStakingCacheManager { + return s.cache +} diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index b2717c6fb8..2022714981 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -10,6 +10,7 @@ import ( "sync" "github.com/iotexproject/iotex-address/address" + "github.com/pkg/errors" "github.com/iotexproject/iotex-core/db/batch" "github.com/iotexproject/iotex-core/pkg/util/byteutil" @@ -39,78 +40,340 @@ func newLiquidStakingDirty(clean liquidStakingCacheReader) *liquidStakingDirty { } } -func (s *liquidStakingDirty) putHeight(h uint64) { - s.batch.Put(_liquidStakingNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") - s.delta.putHeight(h) +func (dirty *liquidStakingDirty) putHeight(h uint64) { + dirty.batch.Put(_liquidStakingNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") + dirty.delta.putHeight(h) } -func (s *liquidStakingDirty) addBucketType(id uint64, bt *BucketType) error { - s.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") - return s.delta.addBucketType(id, bt) +func (dirty *liquidStakingDirty) addBucketType(id uint64, bt *BucketType) error { + dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") + return dirty.delta.addBucketType(id, bt) } -func (s *liquidStakingDirty) updateBucketType(id uint64, bt *BucketType) error { - s.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") - return s.delta.updateBucketType(id, bt) +func (dirty *liquidStakingDirty) updateBucketType(id uint64, bt *BucketType) error { + dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") + return dirty.delta.updateBucketType(id, bt) } -func (s *liquidStakingDirty) addBucketInfo(id uint64, bi *BucketInfo) error { - s.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") - return s.delta.addBucketInfo(id, bi) +func (dirty *liquidStakingDirty) addBucketInfo(id uint64, bi *BucketInfo) error { + dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") + return dirty.delta.addBucketInfo(id, bi) } -func (s *liquidStakingDirty) updateBucketInfo(id uint64, bi *BucketInfo) error { - s.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") - return s.delta.updateBucketInfo(id, bi) +func (dirty *liquidStakingDirty) updateBucketInfo(id uint64, bi *BucketInfo) error { + dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") + return dirty.delta.updateBucketInfo(id, bi) } -func (s *liquidStakingDirty) burnBucket(id uint64) error { - s.batch.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") - return s.delta.deleteBucketInfo(id) +func (dirty *liquidStakingDirty) burnBucket(id uint64) error { + dirty.batch.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") + return dirty.delta.deleteBucketInfo(id) } -func (s *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { - id, ok := s.delta.getBucketTypeIndex(amount, duration) +func (dirty *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { + id, ok := dirty.delta.getBucketTypeIndex(amount, duration) if ok { return id, true } - id, ok = s.clean.getBucketTypeIndex(amount, duration) + id, ok = dirty.clean.getBucketTypeIndex(amount, duration) return id, ok } -func (s *liquidStakingDirty) getBucketTypeCount() uint64 { - return s.clean.getTotalBucketTypeCount() + s.delta.addedBucketTypeCnt() +func (dirty *liquidStakingDirty) getBucketTypeCount() uint64 { + return dirty.clean.getTotalBucketTypeCount() + dirty.delta.addedBucketTypeCnt() } -func (s *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { - bt, ok := s.delta.getBucketType(id) +func (dirty *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { + bt, ok := dirty.delta.getBucketType(id) if ok { return bt, true } - bt, ok = s.clean.getBucketType(id) + bt, ok = dirty.clean.getBucketType(id) return bt, ok } -func (s *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { - if s.delta.isBucketDeleted(id) { +func (dirty *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { + if dirty.delta.isBucketDeleted(id) { return nil, false } - bi, ok := s.delta.getBucketInfo(id) + bi, ok := dirty.delta.getBucketInfo(id) if ok { return bi, true } - bi, ok = s.clean.getBucketInfo(id) + bi, ok = dirty.clean.getBucketInfo(id) return bi, ok } -func (s *liquidStakingDirty) finalizeBatch() batch.KVStoreBatch { - s.once.Do(func() { - total := s.clean.getTotalBucketCount() + s.delta.addedBucketCnt() - s.batch.Put(_liquidStakingNS, _liquidStakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(total), "failed to put total bucket count") +func (dirty *liquidStakingDirty) finalizeBatch() batch.KVStoreBatch { + dirty.once.Do(func() { + total := dirty.clean.getTotalBucketCount() + dirty.delta.addedBucketCnt() + dirty.batch.Put(_liquidStakingNS, _liquidStakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(total), "failed to put total bucket count") }) - return s.batch + return dirty.batch } -func (s *liquidStakingDirty) finalize() (batch.KVStoreBatch, *liquidStakingDelta) { - return s.finalizeBatch(), s.delta +func (dirty *liquidStakingDirty) finalize() (batch.KVStoreBatch, *liquidStakingDelta) { + return dirty.finalizeBatch(), dirty.delta +} + +func (dirty *liquidStakingDirty) handleTransferEvent(event eventParam) error { + to, err := event.indexedFieldAddress("to") + if err != nil { + return err + } + tokenID, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + + dirty.tokenOwner[tokenID.Uint64()] = to + return nil +} + +func (dirty *liquidStakingDirty) handleBucketTypeActivatedEvent(event eventParam, height uint64) error { + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + bt := BucketType{ + Amount: amountParam, + Duration: durationParam.Uint64(), + ActivatedAt: height, + } + id, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) + if !ok { + id = dirty.getBucketTypeCount() + err = dirty.addBucketType(id, &bt) + } else { + err = dirty.updateBucketType(id, &bt) + } + + return err +} + +func (dirty *liquidStakingDirty) handleBucketTypeDeactivatedEvent(event eventParam, height uint64) error { + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + id, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) + } + bt, ok := dirty.getBucketType(id) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", id) + } + bt.ActivatedAt = maxBlockNumber + return dirty.updateBucketType(id, bt) +} + +func (dirty *liquidStakingDirty) handleStakedEvent(event eventParam, height uint64) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + delegateParam, err := event.fieldAddress("delegate") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) + } + bucket := BucketInfo{ + TypeIndex: btIdx, + Delegate: delegateParam, + Owner: dirty.tokenOwner[tokenIDParam.Uint64()], + CreatedAt: height, + UnlockedAt: maxBlockNumber, + UnstakedAt: maxBlockNumber, + } + return dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) +} + +func (dirty *liquidStakingDirty) handleLockedEvent(event eventParam) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + bt, ok := dirty.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) + } + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) + } + b.TypeIndex = newBtIdx + b.UnlockedAt = maxBlockNumber + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleUnlockedEvent(event eventParam, height uint64) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + b.UnlockedAt = height + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleUnstakedEvent(event eventParam, height uint64) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + b.UnstakedAt = height + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleMergedEvent(event eventParam) error { + tokenIDsParam, err := event.fieldUint256Slice("tokenIds") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + // merge to the first bucket + btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) + } + b, ok := dirty.getBucketInfo(tokenIDsParam[0].Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) + } + b.TypeIndex = btIdx + b.UnlockedAt = maxBlockNumber + for i := 1; i < len(tokenIDsParam); i++ { + if err = dirty.burnBucket(tokenIDsParam[i].Uint64()); err != nil { + return err + } + } + return dirty.updateBucketInfo(tokenIDsParam[0].Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleDurationExtendedEvent(event eventParam) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + durationParam, err := event.fieldUint256("duration") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + bt, ok := dirty.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) + } + newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) + } + b.TypeIndex = newBtIdx + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleAmountIncreasedEvent(event eventParam) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + amountParam, err := event.fieldUint256("amount") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + bt, ok := dirty.getBucketType(b.TypeIndex) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) + } + newBtIdx, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) + if !ok { + return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) + } + b.TypeIndex = newBtIdx + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleDelegateChangedEvent(event eventParam) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + delegateParam, err := event.fieldAddress("newDelegate") + if err != nil { + return err + } + + b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) + if !ok { + return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) + } + b.Delegate = delegateParam + return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) +} + +func (dirty *liquidStakingDirty) handleWithdrawalEvent(event eventParam) error { + tokenIDParam, err := event.indexedFieldUint256("tokenId") + if err != nil { + return err + } + + return dirty.burnBucket(tokenIDParam.Uint64()) } diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index eeedeb1bc0..cde32506f6 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -9,11 +9,9 @@ import ( "context" "math/big" "strings" - "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/iotexproject/go-pkgs/hash" "github.com/iotexproject/iotex-address/address" "github.com/iotexproject/iotex-proto/golang/iotextypes" "github.com/pkg/errors" @@ -398,9 +396,8 @@ type ( // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *liquidStakingCacheThreadSafety // in-memory index for clean data - blockInterval time.Duration + kvstore db.KVStore // persistent storage + cache *liquidStakingCacheThreadSafety // in-memory index for clean data } ) @@ -424,11 +421,10 @@ func init() { } // NewLiquidStakingIndexer creates a new liquid staking indexer -func NewLiquidStakingIndexer(kvStore db.KVStore, blockInterval time.Duration) LiquidStakingIndexer { +func NewLiquidStakingIndexer(kvStore db.KVStore) LiquidStakingIndexer { return &liquidStakingIndexer{ - blockInterval: blockInterval, - kvstore: kvStore, - cache: newLiquidStakingCache(), + kvstore: kvStore, + cache: newLiquidStakingCache(), } } @@ -445,6 +441,7 @@ func (s *liquidStakingIndexer) Stop(ctx context.Context) error { if err := s.kvstore.Stop(ctx); err != nil { return err } + s.cache = newLiquidStakingCache() return nil } @@ -453,33 +450,19 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e // new dirty cache for this block // it's not necessary to use thread safe cache here, because only one thread will call this function // and no update to cache will happen before dirty merge to clean - dirty := newLiquidStakingDirty(s.cache.cache) + dirty := newLiquidStakingDirty(s.cache.unsafe()) dirty.putHeight(blk.Height()) - // make action map - actionMap := make(map[hash.Hash256]*action.SealedEnvelope) - for i := range blk.Actions { - h, err := blk.Actions[i].Hash() - if err != nil { - return err - } - actionMap[h] = &blk.Actions[i] - } - // handle events of block for _, receipt := range blk.Receipts { if receipt.Status != uint64(iotextypes.ReceiptStatus_Success) { continue } - act, ok := actionMap[receipt.ActionHash] - if !ok { - return errors.Errorf("action %x not found", receipt.ActionHash) - } for _, log := range receipt.Logs() { if log.Address != LiquidStakingContractAddress { continue } - if err := s.handleEvent(ctx, dirty, blk, act, log); err != nil { + if err := s.handleEvent(ctx, dirty, blk, log); err != nil { return err } } @@ -520,28 +503,14 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { // Bucket returns the bucket func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { - bi, ok := s.cache.getBucketInfo(id) - if !ok { - return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) - } - bt := s.cache.mustGetBucketType(bi.TypeIndex) - vb, err := s.convertToVoteBucket(id, bi, bt) - if err != nil { - return nil, err - } - return vb, nil + return s.generateBucket(id) } // BucketsByIndices returns the buckets by indices func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*Bucket, error) { vbs := make([]*Bucket, 0, len(indices)) for _, id := range indices { - bi, ok := s.cache.getBucketInfo(id) - if !ok { - return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) - } - bt := s.cache.mustGetBucketType(bi.TypeIndex) - vb, err := s.convertToVoteBucket(id, bi, bt) + vb, err := s.generateBucket(id) if err != nil { return nil, err } @@ -558,7 +527,16 @@ func (s *liquidStakingIndexer) ActiveBucketTypes() (map[uint64]*BucketType, erro return s.cache.getActiveBucketType(), nil } -func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, act *action.SealedEnvelope, log *action.Log) error { +func (s *liquidStakingIndexer) generateBucket(id uint64) (*Bucket, error) { + bi, ok := s.cache.getBucketInfo(id) + if !ok { + return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) + } + bt := s.cache.mustGetBucketType(bi.TypeIndex) + return s.convertToVoteBucket(id, bi, bt) +} + +func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, log *action.Log) error { // get event abi abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) if err != nil { @@ -574,296 +552,34 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidSta // handle different kinds of event switch abiEvent.Name { case "BucketTypeActivated": - return s.handleBucketTypeActivatedEvent(dirty, event, blk.Height()) + return dirty.handleBucketTypeActivatedEvent(event, blk.Height()) case "BucketTypeDeactivated": - return s.handleBucketTypeDeactivatedEvent(dirty, event, blk.Height()) + return dirty.handleBucketTypeDeactivatedEvent(event, blk.Height()) case "Staked": - return s.handleStakedEvent(dirty, event, blk.Height()) + return dirty.handleStakedEvent(event, blk.Height()) case "Locked": - return s.handleLockedEvent(dirty, event) + return dirty.handleLockedEvent(event) case "Unlocked": - return s.handleUnlockedEvent(dirty, event, blk.Height()) + return dirty.handleUnlockedEvent(event, blk.Height()) case "Unstaked": - return s.handleUnstakedEvent(dirty, event, blk.Height()) + return dirty.handleUnstakedEvent(event, blk.Height()) case "Merged": - return s.handleMergedEvent(dirty, event) + return dirty.handleMergedEvent(event) case "DurationExtended": - return s.handleDurationExtendedEvent(dirty, event) + return dirty.handleDurationExtendedEvent(event) case "AmountIncreased": - return s.handleAmountIncreasedEvent(dirty, event) + return dirty.handleAmountIncreasedEvent(event) case "DelegateChanged": - return s.handleDelegateChangedEvent(dirty, event) + return dirty.handleDelegateChangedEvent(event) case "Withdrawal": - return s.handleWithdrawalEvent(dirty, event) + return dirty.handleWithdrawalEvent(event) case "Transfer": - return s.handleTransferEvent(dirty, event) + return dirty.handleTransferEvent(event) default: return nil } } -func (s *liquidStakingIndexer) handleTransferEvent(dirty *liquidStakingDirty, event eventParam) error { - to, err := event.indexedFieldAddress("to") - if err != nil { - return err - } - tokenID, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - - dirty.tokenOwner[tokenID.Uint64()] = to - return nil -} - -func (s *liquidStakingIndexer) handleBucketTypeActivatedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { - amountParam, err := event.fieldUint256("amount") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - bt := BucketType{ - Amount: amountParam, - Duration: durationParam.Uint64(), - ActivatedAt: height, - } - id, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) - if !ok { - id = dirty.getBucketTypeCount() - err = dirty.addBucketType(id, &bt) - } else { - err = dirty.updateBucketType(id, &bt) - } - - return err -} - -func (s *liquidStakingIndexer) handleBucketTypeDeactivatedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { - amountParam, err := event.fieldUint256("amount") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - id, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) - } - bt, ok := dirty.getBucketType(id) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "id %d", id) - } - bt.ActivatedAt = maxBlockNumber - return dirty.updateBucketType(id, bt) -} - -func (s *liquidStakingIndexer) handleStakedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - delegateParam, err := event.fieldAddress("delegate") - if err != nil { - return err - } - amountParam, err := event.fieldUint256("amount") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) - } - bucket := BucketInfo{ - TypeIndex: btIdx, - Delegate: delegateParam, - Owner: dirty.tokenOwner[tokenIDParam.Uint64()], - CreatedAt: height, - UnlockedAt: maxBlockNumber, - UnstakedAt: maxBlockNumber, - } - return dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) -} - -func (s *liquidStakingIndexer) handleLockedEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - bt, ok := dirty.getBucketType(b.TypeIndex) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) - } - newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %v, duration %d", bt.Amount, durationParam.Uint64()) - } - b.TypeIndex = newBtIdx - b.UnlockedAt = maxBlockNumber - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleUnlockedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - b.UnlockedAt = height - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleUnstakedEvent(dirty *liquidStakingDirty, event eventParam, height uint64) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - b.UnstakedAt = height - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleMergedEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDsParam, err := event.fieldUint256Slice("tokenIds") - if err != nil { - return err - } - amountParam, err := event.fieldUint256("amount") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - // merge to the first bucket - btIdx, ok := dirty.getBucketTypeIndex(amountParam, durationParam.Uint64()) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) - } - b, ok := dirty.getBucketInfo(tokenIDsParam[0].Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDsParam[0].Uint64()) - } - b.TypeIndex = btIdx - b.UnlockedAt = maxBlockNumber - for i := 1; i < len(tokenIDsParam); i++ { - if err = dirty.burnBucket(tokenIDsParam[i].Uint64()); err != nil { - return err - } - } - return dirty.updateBucketInfo(tokenIDsParam[0].Uint64(), b) -} - -func (s *liquidStakingIndexer) handleDurationExtendedEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - durationParam, err := event.fieldUint256("duration") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - bt, ok := dirty.getBucketType(b.TypeIndex) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) - } - newBtIdx, ok := dirty.getBucketTypeIndex(bt.Amount, durationParam.Uint64()) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", bt.Amount.Int64(), durationParam.Uint64()) - } - b.TypeIndex = newBtIdx - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleAmountIncreasedEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - amountParam, err := event.fieldUint256("amount") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - bt, ok := dirty.getBucketType(b.TypeIndex) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "id %d", b.TypeIndex) - } - newBtIdx, ok := dirty.getBucketTypeIndex(amountParam, bt.Duration) - if !ok { - return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), bt.Duration) - } - b.TypeIndex = newBtIdx - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleDelegateChangedEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - delegateParam, err := event.fieldAddress("newDelegate") - if err != nil { - return err - } - - b, ok := dirty.getBucketInfo(tokenIDParam.Uint64()) - if !ok { - return errors.Wrapf(ErrBucketInfoNotExist, "token id %d", tokenIDParam.Uint64()) - } - b.Delegate = delegateParam - return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) -} - -func (s *liquidStakingIndexer) handleWithdrawalEvent(dirty *liquidStakingDirty, event eventParam) error { - tokenIDParam, err := event.indexedFieldUint256("tokenId") - if err != nil { - return err - } - - return dirty.burnBucket(tokenIDParam.Uint64()) -} - func (s *liquidStakingIndexer) loadCache() error { delta := newLiquidStakingDelta() // load height @@ -894,10 +610,8 @@ func (s *liquidStakingIndexer) loadCache() error { // load bucket info ks, vs, err := s.kvstore.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrBucketNotExist) { - return err - } + if err != nil && !errors.Is(err, db.ErrBucketNotExist) { + return err } for i := range vs { var b BucketInfo @@ -909,10 +623,8 @@ func (s *liquidStakingIndexer) loadCache() error { // load bucket type ks, vs, err = s.kvstore.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) - if err != nil { - if !errors.Is(err, db.ErrBucketNotExist) { - return err - } + if err != nil && !errors.Is(err, db.ErrBucketNotExist) { + return err } for i := range vs { var b BucketType @@ -935,10 +647,6 @@ func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { return nil } -func (s *liquidStakingIndexer) blockHeightToDuration(height uint64) time.Duration { - return time.Duration(height) * s.blockInterval -} - func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { vb := Bucket{ Index: token, diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 665ba6643c..a205b7c586 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1700,7 +1700,7 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r r.NoError(err) cc := cfg.DB cc.DbPath = testLiquidStakeIndexerPath - liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc), cfg.Genesis.BlockInterval) + liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc)) // create BlockDAO dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) r.NotNil(dao) From 29899335b4f573de682cf037f7eded21c13920bb Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 17 May 2023 19:14:04 +0800 Subject: [PATCH 41/51] lock during multiple cache read --- blockindex/liquidstaking_indexer.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index cde32506f6..033b4f5547 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -9,6 +9,7 @@ import ( "context" "math/big" "strings" + "sync" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -398,6 +399,7 @@ type ( liquidStakingIndexer struct { kvstore db.KVStore // persistent storage cache *liquidStakingCacheThreadSafety // in-memory index for clean data + mutex sync.RWMutex // mutex for multiple reading to cache } ) @@ -489,6 +491,9 @@ func (s *liquidStakingIndexer) CandidateVotes(candidate address.Address) *big.In // Buckets returns the buckets func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + vbs := []*Bucket{} for id, bi := range s.cache.getAllBucketInfo() { bt := s.cache.mustGetBucketType(bi.TypeIndex) @@ -503,11 +508,17 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { // Bucket returns the bucket func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + return s.generateBucket(id) } // BucketsByIndices returns the buckets by indices func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*Bucket, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + vbs := make([]*Bucket, 0, len(indices)) for _, id := range indices { vb, err := s.generateBucket(id) @@ -637,6 +648,9 @@ func (s *liquidStakingIndexer) loadCache() error { } func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { + s.mutex.Lock() + defer s.mutex.Unlock() + batch, delta := dirty.finalize() if err := s.kvstore.WriteBatch(batch); err != nil { return err From c369d1985727e5997f5502bf482141867ede99a4 Mon Sep 17 00:00:00 2001 From: envestcc Date: Wed, 17 May 2023 21:57:00 +0800 Subject: [PATCH 42/51] fix test --- e2etest/liquid_staking_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index a205b7c586..98ee804401 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1718,7 +1718,7 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r // r.NoError(reward.Register(registry)) r.NotNil(bc) - execution := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGas) + execution := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGasWithSGD, nil) r.NoError(execution.Register(registry)) r.NoError(bc.Start(ctx)) From bd5887c86d6ae8956c88d357bd9d624d9307627d Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 11:00:27 +0800 Subject: [PATCH 43/51] rename LiquidStakingIndexer to ContractStakingIndexer --- blockindex/liquidstaking_bucket.go | 46 +++++++++--------- blockindex/liquidstaking_cache.go | 64 ++++++++++++------------- blockindex/liquidstaking_cache_test.go | 2 +- blockindex/liquidstaking_delta.go | 8 ++-- blockindex/liquidstaking_dirty.go | 16 +++---- blockindex/liquidstaking_indexer.go | 66 ++++++++++++++------------ e2etest/liquid_staking_test.go | 32 ++++++------- 7 files changed, 120 insertions(+), 114 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index 7ec676eff5..cc2eee0985 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -22,8 +22,8 @@ const ( ) type ( - // BucketInfo is the bucket information - BucketInfo struct { + // ContractStakingBucketInfo is the bucket information + ContractStakingBucketInfo struct { TypeIndex uint64 CreatedAt uint64 UnlockedAt uint64 @@ -32,28 +32,28 @@ type ( Owner address.Address } - // BucketType is the bucket type - BucketType struct { + // ContractStakingBucketType is the bucket type + ContractStakingBucketType struct { Amount *big.Int Duration uint64 ActivatedAt uint64 } - // Bucket is the bucket information including bucket type and bucket info - Bucket struct { - Index uint64 - Candidate address.Address - Owner address.Address - StakedAmount *big.Int - StakedDuration uint64 - CreateTime uint64 - StakeStartTime uint64 - UnstakeStartTime uint64 - AutoStake bool + // ContractStakingBucket is the bucket information including bucket type and bucket info + ContractStakingBucket struct { + Index uint64 + Candidate address.Address + Owner address.Address + StakedAmount *big.Int + StakedDurationBlockNumber uint64 + CreateBlockHeight uint64 + StakeBlockHeight uint64 + UnstakeBlockHeight uint64 + AutoStake bool } ) -func (bt *BucketType) toProto() *indexpb.BucketType { +func (bt *ContractStakingBucketType) toProto() *indexpb.BucketType { return &indexpb.BucketType{ Amount: bt.Amount.String(), Duration: bt.Duration, @@ -61,7 +61,7 @@ func (bt *BucketType) toProto() *indexpb.BucketType { } } -func (bt *BucketType) loadProto(p *indexpb.BucketType) error { +func (bt *ContractStakingBucketType) loadProto(p *indexpb.BucketType) error { var ok bool bt.Amount, ok = big.NewInt(0).SetString(p.Amount, 10) if !ok { @@ -72,11 +72,11 @@ func (bt *BucketType) loadProto(p *indexpb.BucketType) error { return nil } -func (bt *BucketType) serialize() []byte { +func (bt *ContractStakingBucketType) serialize() []byte { return byteutil.Must(proto.Marshal(bt.toProto())) } -func (bt *BucketType) deserialize(b []byte) error { +func (bt *ContractStakingBucketType) deserialize(b []byte) error { m := indexpb.BucketType{} if err := proto.Unmarshal(b, &m); err != nil { return err @@ -84,7 +84,7 @@ func (bt *BucketType) deserialize(b []byte) error { return bt.loadProto(&m) } -func (bi *BucketInfo) toProto() *indexpb.BucketInfo { +func (bi *ContractStakingBucketInfo) toProto() *indexpb.BucketInfo { pb := &indexpb.BucketInfo{ TypeIndex: bi.TypeIndex, Delegate: bi.Delegate.String(), @@ -96,11 +96,11 @@ func (bi *BucketInfo) toProto() *indexpb.BucketInfo { return pb } -func (bi *BucketInfo) serialize() []byte { +func (bi *ContractStakingBucketInfo) serialize() []byte { return byteutil.Must(proto.Marshal(bi.toProto())) } -func (bi *BucketInfo) deserialize(b []byte) error { +func (bi *ContractStakingBucketInfo) deserialize(b []byte) error { m := indexpb.BucketInfo{} if err := proto.Unmarshal(b, &m); err != nil { return err @@ -108,7 +108,7 @@ func (bi *BucketInfo) deserialize(b []byte) error { return bi.loadProto(&m) } -func (bi *BucketInfo) loadProto(p *indexpb.BucketInfo) error { +func (bi *ContractStakingBucketInfo) loadProto(p *indexpb.BucketInfo) error { var err error bi.TypeIndex = p.TypeIndex bi.CreatedAt = p.CreatedAt diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index ab0c2d5f8f..28ab0e2b5b 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -20,12 +20,12 @@ type ( getTotalBucketCount() uint64 getTotalBucketTypeCount() uint64 getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) - getBucketType(id uint64) (*BucketType, bool) - getBucketInfo(id uint64) (*BucketInfo, bool) - mustGetBucketType(id uint64) *BucketType - mustGetBucketInfo(id uint64) *BucketInfo - getAllBucketInfo() map[uint64]*BucketInfo - getActiveBucketType() map[uint64]*BucketType + getBucketType(id uint64) (*ContractStakingBucketType, bool) + getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) + mustGetBucketType(id uint64) *ContractStakingBucketType + mustGetBucketInfo(id uint64) *ContractStakingBucketInfo + getAllBucketInfo() map[uint64]*ContractStakingBucketInfo + getActiveBucketType() map[uint64]*ContractStakingBucketType getCandidateVotes(candidate address.Address) *big.Int } @@ -36,16 +36,16 @@ type ( merge(delta *liquidStakingDelta) error putHeight(h uint64) putTotalBucketCount(cnt uint64) - putBucketType(id uint64, bt *BucketType) - putBucketInfo(id uint64, bi *BucketInfo) + putBucketType(id uint64, bt *ContractStakingBucketType) + putBucketInfo(id uint64, bi *ContractStakingBucketInfo) deleteBucketInfo(id uint64) } liquidStakingCache struct { - idBucketMap map[uint64]*BucketInfo // map[token]BucketInfo - candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket - idBucketTypeMap map[uint64]*BucketType // map[token]BucketType - propertyBucketTypeMap map[int64]map[uint64]uint64 // map[amount][duration]index + idBucketMap map[uint64]*ContractStakingBucketInfo // map[token]BucketInfo + candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket + idBucketTypeMap map[uint64]*ContractStakingBucketType // map[token]BucketType + propertyBucketTypeMap map[int64]map[uint64]uint64 // map[amount][duration]index height uint64 totalBucketCount uint64 // total number of buckets including burned buckets } @@ -58,8 +58,8 @@ type ( func newLiquidStakingCache() *liquidStakingCacheThreadSafety { cache := &liquidStakingCache{ - idBucketMap: make(map[uint64]*BucketInfo), - idBucketTypeMap: make(map[uint64]*BucketType), + idBucketMap: make(map[uint64]*ContractStakingBucketInfo), + idBucketTypeMap: make(map[uint64]*ContractStakingBucketType), propertyBucketTypeMap: make(map[int64]map[uint64]uint64), candidateBucketMap: make(map[string]map[uint64]bool), } @@ -74,7 +74,7 @@ func (s *liquidStakingCache) getHeight() uint64 { return s.height } -func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { +func (s *liquidStakingCache) putBucketType(id uint64, bt *ContractStakingBucketType) { amount := bt.Amount.Int64() s.idBucketTypeMap[id] = bt m, ok := s.propertyBucketTypeMap[amount] @@ -85,7 +85,7 @@ func (s *liquidStakingCache) putBucketType(id uint64, bt *BucketType) { m[bt.Duration] = id } -func (s *liquidStakingCache) putBucketInfo(id uint64, bi *BucketInfo) { +func (s *liquidStakingCache) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { s.idBucketMap[id] = bi if _, ok := s.candidateBucketMap[bi.Delegate.String()]; !ok { s.candidateBucketMap[bi.Delegate.String()] = make(map[uint64]bool) @@ -114,12 +114,12 @@ func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration uint64 return id, ok } -func (s *liquidStakingCache) getBucketType(id uint64) (*BucketType, bool) { +func (s *liquidStakingCache) getBucketType(id uint64) (*ContractStakingBucketType, bool) { bt, ok := s.idBucketTypeMap[id] return bt, ok } -func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { +func (s *liquidStakingCache) mustGetBucketType(id uint64) *ContractStakingBucketType { bt, ok := s.idBucketTypeMap[id] if !ok { panic("bucket type not found") @@ -127,12 +127,12 @@ func (s *liquidStakingCache) mustGetBucketType(id uint64) *BucketType { return bt } -func (s *liquidStakingCache) getBucketInfo(id uint64) (*BucketInfo, bool) { +func (s *liquidStakingCache) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { bi, ok := s.idBucketMap[id] return bi, ok } -func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *BucketInfo { +func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { bt, ok := s.idBucketMap[id] if !ok { panic("bucket info not found") @@ -175,16 +175,16 @@ func (s *liquidStakingCache) getTotalBucketTypeCount() uint64 { return uint64(len(s.idBucketTypeMap)) } -func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*BucketInfo { - m := make(map[uint64]*BucketInfo) +func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { + m := make(map[uint64]*ContractStakingBucketInfo) for k, v := range s.idBucketMap { m[k] = v } return m } -func (s *liquidStakingCache) getActiveBucketType() map[uint64]*BucketType { - m := make(map[uint64]*BucketType) +func (s *liquidStakingCache) getActiveBucketType() map[uint64]*ContractStakingBucketType { + m := make(map[uint64]*ContractStakingBucketType) for k, v := range s.idBucketTypeMap { if v.ActivatedAt != maxBlockNumber { m[k] = v @@ -224,14 +224,14 @@ func (s *liquidStakingCacheThreadSafety) getHeight() uint64 { return s.cache.getHeight() } -func (s *liquidStakingCacheThreadSafety) putBucketType(id uint64, bt *BucketType) { +func (s *liquidStakingCacheThreadSafety) putBucketType(id uint64, bt *ContractStakingBucketType) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.putBucketType(id, bt) } -func (s *liquidStakingCacheThreadSafety) putBucketInfo(id uint64, bi *BucketInfo) { +func (s *liquidStakingCacheThreadSafety) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { s.mutex.Lock() defer s.mutex.Unlock() @@ -252,28 +252,28 @@ func (s *liquidStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, dur return s.cache.getBucketTypeIndex(amount, duration) } -func (s *liquidStakingCacheThreadSafety) getBucketType(id uint64) (*BucketType, bool) { +func (s *liquidStakingCacheThreadSafety) getBucketType(id uint64) (*ContractStakingBucketType, bool) { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketType(id) } -func (s *liquidStakingCacheThreadSafety) mustGetBucketType(id uint64) *BucketType { +func (s *liquidStakingCacheThreadSafety) mustGetBucketType(id uint64) *ContractStakingBucketType { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.mustGetBucketType(id) } -func (s *liquidStakingCacheThreadSafety) getBucketInfo(id uint64) (*BucketInfo, bool) { +func (s *liquidStakingCacheThreadSafety) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *BucketInfo { +func (s *liquidStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { s.mutex.RLock() defer s.mutex.RUnlock() @@ -308,14 +308,14 @@ func (s *liquidStakingCacheThreadSafety) getTotalBucketTypeCount() uint64 { return s.cache.getTotalBucketTypeCount() } -func (s *liquidStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*BucketInfo { +func (s *liquidStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getAllBucketInfo() } -func (s *liquidStakingCacheThreadSafety) getActiveBucketType() map[uint64]*BucketType { +func (s *liquidStakingCacheThreadSafety) getActiveBucketType() map[uint64]*ContractStakingBucketType { s.mutex.RLock() defer s.mutex.RUnlock() diff --git a/blockindex/liquidstaking_cache_test.go b/blockindex/liquidstaking_cache_test.go index 28445ea16f..f4d2637cd5 100644 --- a/blockindex/liquidstaking_cache_test.go +++ b/blockindex/liquidstaking_cache_test.go @@ -18,7 +18,7 @@ func TestLiquidStakingCacheThreadSafety(t *testing.T) { wait.Add(2) go func() { for i := 0; i < 1000; i++ { - cache.putBucketType(uint64(i), &BucketType{ + cache.putBucketType(uint64(i), &ContractStakingBucketType{ Amount: big.NewInt(int64(i)), Duration: 1000, ActivatedAt: 10, diff --git a/blockindex/liquidstaking_delta.go b/blockindex/liquidstaking_delta.go index 71f1a0a0cf..c13acb2b57 100644 --- a/blockindex/liquidstaking_delta.go +++ b/blockindex/liquidstaking_delta.go @@ -67,7 +67,7 @@ func newLiquidStakingDelta() *liquidStakingDelta { } } -func (s *liquidStakingDelta) addBucketType(id uint64, bt *BucketType) error { +func (s *liquidStakingDelta) addBucketType(id uint64, bt *ContractStakingBucketType) error { if _, ok := s.bucketTypeDeltaState[id]; !ok { s.bucketTypeDeltaState[id] = deltaStateAdded } else { @@ -81,7 +81,7 @@ func (s *liquidStakingDelta) addBucketType(id uint64, bt *BucketType) error { return nil } -func (s *liquidStakingDelta) updateBucketType(id uint64, bt *BucketType) error { +func (s *liquidStakingDelta) updateBucketType(id uint64, bt *ContractStakingBucketType) error { if _, ok := s.bucketTypeDeltaState[id]; !ok { s.bucketTypeDeltaState[id] = deltaStateModified } else { @@ -95,7 +95,7 @@ func (s *liquidStakingDelta) updateBucketType(id uint64, bt *BucketType) error { return nil } -func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *BucketInfo) error { +func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { var err error if _, ok := s.bucketInfoDeltaState[id]; !ok { s.bucketInfoDeltaState[id] = deltaStateAdded @@ -109,7 +109,7 @@ func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *BucketInfo) error { return nil } -func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *BucketInfo) error { +func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { if _, ok := s.bucketInfoDeltaState[id]; !ok { s.bucketInfoDeltaState[id] = deltaStateModified } else { diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 2022714981..65fc2e4f13 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -45,22 +45,22 @@ func (dirty *liquidStakingDirty) putHeight(h uint64) { dirty.delta.putHeight(h) } -func (dirty *liquidStakingDirty) addBucketType(id uint64, bt *BucketType) error { +func (dirty *liquidStakingDirty) addBucketType(id uint64, bt *ContractStakingBucketType) error { dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") return dirty.delta.addBucketType(id, bt) } -func (dirty *liquidStakingDirty) updateBucketType(id uint64, bt *BucketType) error { +func (dirty *liquidStakingDirty) updateBucketType(id uint64, bt *ContractStakingBucketType) error { dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") return dirty.delta.updateBucketType(id, bt) } -func (dirty *liquidStakingDirty) addBucketInfo(id uint64, bi *BucketInfo) error { +func (dirty *liquidStakingDirty) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") return dirty.delta.addBucketInfo(id, bi) } -func (dirty *liquidStakingDirty) updateBucketInfo(id uint64, bi *BucketInfo) error { +func (dirty *liquidStakingDirty) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") return dirty.delta.updateBucketInfo(id, bi) } @@ -83,7 +83,7 @@ func (dirty *liquidStakingDirty) getBucketTypeCount() uint64 { return dirty.clean.getTotalBucketTypeCount() + dirty.delta.addedBucketTypeCnt() } -func (dirty *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { +func (dirty *liquidStakingDirty) getBucketType(id uint64) (*ContractStakingBucketType, bool) { bt, ok := dirty.delta.getBucketType(id) if ok { return bt, true @@ -92,7 +92,7 @@ func (dirty *liquidStakingDirty) getBucketType(id uint64) (*BucketType, bool) { return bt, ok } -func (dirty *liquidStakingDirty) getBucketInfo(id uint64) (*BucketInfo, bool) { +func (dirty *liquidStakingDirty) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { if dirty.delta.isBucketDeleted(id) { return nil, false } @@ -140,7 +140,7 @@ func (dirty *liquidStakingDirty) handleBucketTypeActivatedEvent(event eventParam return err } - bt := BucketType{ + bt := ContractStakingBucketType{ Amount: amountParam, Duration: durationParam.Uint64(), ActivatedAt: height, @@ -200,7 +200,7 @@ func (dirty *liquidStakingDirty) handleStakedEvent(event eventParam, height uint if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } - bucket := BucketInfo{ + bucket := ContractStakingBucketInfo{ TypeIndex: btIdx, Delegate: delegateParam, Owner: dirty.tokenOwner[tokenIDParam.Uint64()], diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 033b4f5547..01969fe84e 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -374,19 +374,25 @@ const ( ) type ( - // LiquidStakingIndexer is the interface of liquid staking indexer - LiquidStakingIndexer interface { + // ContractStakingIndexer is the interface of contract staking indexer + ContractStakingIndexer interface { blockdao.BlockIndexer + // CandidateVotes returns the total votes of a candidate CandidateVotes(candidate address.Address) *big.Int - Buckets() ([]*Bucket, error) - Bucket(id uint64) (*Bucket, error) - BucketsByIndices(indices []uint64) ([]*Bucket, error) + // Buckets returns all existed buckets + Buckets() ([]*ContractStakingBucket, error) + // Bucket returns the bucket by id + Bucket(id uint64) (*ContractStakingBucket, error) + // BucketsByIndices returns buckets by indices + BucketsByIndices(indices []uint64) ([]*ContractStakingBucket, error) + // TotalBucketCount returns the total bucket count including burned buckets TotalBucketCount() uint64 - ActiveBucketTypes() (map[uint64]*BucketType, error) + // ActiveBucketTypes returns all active bucket types + ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) } - // liquidStakingIndexer is the implementation of LiquidStakingIndexer + // liquidStakingIndexer is the implementation of ContractStakingIndexer // Main functions: // 1. handle liquid staking contract events when new block comes to generate index data // 2. provide query interface for liquid staking index data @@ -422,8 +428,8 @@ func init() { } } -// NewLiquidStakingIndexer creates a new liquid staking indexer -func NewLiquidStakingIndexer(kvStore db.KVStore) LiquidStakingIndexer { +// NewContractStakingIndexer creates a new contract staking indexer +func NewContractStakingIndexer(kvStore db.KVStore) ContractStakingIndexer { return &liquidStakingIndexer{ kvstore: kvStore, cache: newLiquidStakingCache(), @@ -490,11 +496,11 @@ func (s *liquidStakingIndexer) CandidateVotes(candidate address.Address) *big.In } // Buckets returns the buckets -func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { +func (s *liquidStakingIndexer) Buckets() ([]*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() - vbs := []*Bucket{} + vbs := []*ContractStakingBucket{} for id, bi := range s.cache.getAllBucketInfo() { bt := s.cache.mustGetBucketType(bi.TypeIndex) vb, err := s.convertToVoteBucket(id, bi, bt) @@ -507,7 +513,7 @@ func (s *liquidStakingIndexer) Buckets() ([]*Bucket, error) { } // Bucket returns the bucket -func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { +func (s *liquidStakingIndexer) Bucket(id uint64) (*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() @@ -515,11 +521,11 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*Bucket, error) { } // BucketsByIndices returns the buckets by indices -func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*Bucket, error) { +func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() - vbs := make([]*Bucket, 0, len(indices)) + vbs := make([]*ContractStakingBucket, 0, len(indices)) for _, id := range indices { vb, err := s.generateBucket(id) if err != nil { @@ -534,11 +540,11 @@ func (s *liquidStakingIndexer) TotalBucketCount() uint64 { return s.cache.getTotalBucketCount() } -func (s *liquidStakingIndexer) ActiveBucketTypes() (map[uint64]*BucketType, error) { +func (s *liquidStakingIndexer) ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) { return s.cache.getActiveBucketType(), nil } -func (s *liquidStakingIndexer) generateBucket(id uint64) (*Bucket, error) { +func (s *liquidStakingIndexer) generateBucket(id uint64) (*ContractStakingBucket, error) { bi, ok := s.cache.getBucketInfo(id) if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) @@ -625,7 +631,7 @@ func (s *liquidStakingIndexer) loadCache() error { return err } for i := range vs { - var b BucketInfo + var b ContractStakingBucketInfo if err := b.deserialize(vs[i]); err != nil { return err } @@ -638,7 +644,7 @@ func (s *liquidStakingIndexer) loadCache() error { return err } for i := range vs { - var b BucketType + var b ContractStakingBucketType if err := b.deserialize(vs[i]); err != nil { return err } @@ -661,20 +667,20 @@ func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { return nil } -func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *BucketInfo, bt *BucketType) (*Bucket, error) { - vb := Bucket{ - Index: token, - StakedAmount: bt.Amount, - StakedDuration: bt.Duration, - CreateTime: bi.CreatedAt, - StakeStartTime: bi.CreatedAt, - UnstakeStartTime: bi.UnstakedAt, - AutoStake: bi.UnlockedAt == maxBlockNumber, - Candidate: bi.Delegate, - Owner: bi.Owner, +func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *ContractStakingBucketInfo, bt *ContractStakingBucketType) (*ContractStakingBucket, error) { + vb := ContractStakingBucket{ + Index: token, + StakedAmount: bt.Amount, + StakedDurationBlockNumber: bt.Duration, + CreateBlockHeight: bi.CreatedAt, + StakeBlockHeight: bi.CreatedAt, + UnstakeBlockHeight: bi.UnstakedAt, + AutoStake: bi.UnlockedAt == maxBlockNumber, + Candidate: bi.Delegate, + Owner: bi.Owner, } if bi.UnlockedAt != maxBlockNumber { - vb.StakeStartTime = bi.UnlockedAt + vb.StakeBlockHeight = bi.UnlockedAt } return &vb, nil } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 98ee804401..c90b675c97 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1347,7 +1347,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipt.Status) } - simpleStake := func(cand common.Address, amount, duration *big.Int) *blockindex.Bucket { + simpleStake := func(cand common.Address, amount, duration *big.Int) *blockindex.ContractStakingBucket { return stake(lsdABI, bc, sf, dao, ap, contractAddresses, indexer, r, cand, amount, duration) } @@ -1369,7 +1369,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) buckets, err := indexer.Buckets() r.NoError(err) - slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + slices.SortFunc(buckets, func(i, j *blockindex.ContractStakingBucket) bool { return i.Index < j.Index }) bt := buckets[len(buckets)-1] @@ -1379,10 +1379,10 @@ func TestLiquidStaking(t *testing.T) { r.Equal(identityset.Address(delegateIdx).String(), bt.Candidate.String()) r.EqualValues(identityset.PrivateKey(adminID).PublicKey().Address().String(), bt.Owner.String()) r.EqualValues(0, bt.StakedAmount.Cmp(big.NewInt(10))) - r.EqualValues(10, bt.StakedDuration) - r.EqualValues(blk.Height(), bt.CreateTime) - r.EqualValues(blk.Height(), bt.StakeStartTime) - r.True(bt.UnstakeStartTime == math.MaxUint64) + r.EqualValues(10, bt.StakedDurationBlockNumber) + r.EqualValues(blk.Height(), bt.CreateBlockHeight) + r.EqualValues(blk.Height(), bt.StakeBlockHeight) + r.True(bt.UnstakeBlockHeight == math.MaxUint64) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1403,7 +1403,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Height(), bt.StakeStartTime) + r.EqualValues(blk.Height(), bt.StakeBlockHeight) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1425,7 +1425,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err := indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(blk.Height(), bt.UnstakeStartTime) + r.EqualValues(blk.Height(), bt.UnstakeBlockHeight) r.EqualValues(0, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) @@ -1520,7 +1520,7 @@ func TestLiquidStaking(t *testing.T) { } buckets, err := indexer.Buckets() r.NoError(err) - slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + slices.SortFunc(buckets, func(i, j *blockindex.ContractStakingBucket) bool { return i.Index < j.Index }) r.True(len(buckets) >= 10) @@ -1548,7 +1548,7 @@ func TestLiquidStaking(t *testing.T) { if i == 0 { bt, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.NoError(err) - r.EqualValues(100, bt.StakedDuration) + r.EqualValues(100, bt.StakedDurationBlockNumber) } else { _, err := indexer.Bucket(uint64(newBuckets[i].Index)) r.ErrorIs(err, blockindex.ErrBucketInfoNotExist) @@ -1560,7 +1560,7 @@ func TestLiquidStaking(t *testing.T) { // stake bt := simpleStake(_delegates[3], big.NewInt(10), big.NewInt(10)) tokenID := bt.Index - r.EqualValues(10, bt.StakedDuration) + r.EqualValues(10, bt.StakedDurationBlockNumber) // extend duration data, err := lsdABI.Pack("extendDuration", big.NewInt(int64(tokenID)), big.NewInt(100)) r.NoError(err) @@ -1577,7 +1577,7 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) bt, err = indexer.Bucket(uint64(tokenID)) r.NoError(err) - r.EqualValues(100, bt.StakedDuration) + r.EqualValues(100, bt.StakedDurationBlockNumber) }) t.Run("increase amount", func(t *testing.T) { @@ -1632,7 +1632,7 @@ func TestLiquidStaking(t *testing.T) { } -func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.LiquidStakingIndexer) { +func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.ContractStakingIndexer) { defer func() { delete(cfg.Plugins, config.GatewayPlugin) }() @@ -1700,7 +1700,7 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r r.NoError(err) cc := cfg.DB cc.DbPath = testLiquidStakeIndexerPath - liquidStakeIndexer := blockindex.NewLiquidStakingIndexer(db.NewBoltDB(cc)) + liquidStakeIndexer := blockindex.NewContractStakingIndexer(db.NewBoltDB(cc)) // create BlockDAO dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) r.NotNil(dao) @@ -1845,7 +1845,7 @@ func jumpBlocks(bc blockchain.Blockchain, count int, r *require.Assertions) { } } -func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blockdao.BlockDAO, ap actpool.ActPool, contractAddresses string, indexer blockindex.LiquidStakingIndexer, r *require.Assertions, cand common.Address, amount, duration *big.Int) *blockindex.Bucket { +func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blockdao.BlockDAO, ap actpool.ActPool, contractAddresses string, indexer blockindex.ContractStakingIndexer, r *require.Assertions, cand common.Address, amount, duration *big.Int) *blockindex.ContractStakingBucket { delegate := cand data, err := lsdABI.Pack("stake0", duration, delegate) r.NoError(err) @@ -1862,7 +1862,7 @@ func stake(lsdABI abi.ABI, bc blockchain.Blockchain, sf factory.Factory, dao blo r.EqualValues(iotextypes.ReceiptStatus_Success, receipts[0].Status) buckets, err := indexer.Buckets() r.NoError(err) - slices.SortFunc(buckets, func(i, j *blockindex.Bucket) bool { + slices.SortFunc(buckets, func(i, j *blockindex.ContractStakingBucket) bool { return i.Index < j.Index }) bt := buckets[len(buckets)-1] From 60a203796eef797d83c2a435914d276eb3a78699 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 11:24:54 +0800 Subject: [PATCH 44/51] add contractaddress in bucket --- blockindex/liquidstaking_bucket.go | 1 + blockindex/liquidstaking_indexer.go | 7 ++++--- e2etest/liquid_staking_test.go | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index cc2eee0985..ad4da0ecaa 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -50,6 +50,7 @@ type ( StakeBlockHeight uint64 UnstakeBlockHeight uint64 AutoStake bool + ContractAddress string } ) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 01969fe84e..03098ef682 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -503,7 +503,7 @@ func (s *liquidStakingIndexer) Buckets() ([]*ContractStakingBucket, error) { vbs := []*ContractStakingBucket{} for id, bi := range s.cache.getAllBucketInfo() { bt := s.cache.mustGetBucketType(bi.TypeIndex) - vb, err := s.convertToVoteBucket(id, bi, bt) + vb, err := s.assembleContractStakingBucket(id, bi, bt) if err != nil { return nil, err } @@ -550,7 +550,7 @@ func (s *liquidStakingIndexer) generateBucket(id uint64) (*ContractStakingBucket return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) } bt := s.cache.mustGetBucketType(bi.TypeIndex) - return s.convertToVoteBucket(id, bi, bt) + return s.assembleContractStakingBucket(id, bi, bt) } func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, log *action.Log) error { @@ -667,7 +667,7 @@ func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { return nil } -func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *ContractStakingBucketInfo, bt *ContractStakingBucketType) (*ContractStakingBucket, error) { +func (s *liquidStakingIndexer) assembleContractStakingBucket(token uint64, bi *ContractStakingBucketInfo, bt *ContractStakingBucketType) (*ContractStakingBucket, error) { vb := ContractStakingBucket{ Index: token, StakedAmount: bt.Amount, @@ -678,6 +678,7 @@ func (s *liquidStakingIndexer) convertToVoteBucket(token uint64, bi *ContractSta AutoStake: bi.UnlockedAt == maxBlockNumber, Candidate: bi.Delegate, Owner: bi.Owner, + ContractAddress: LiquidStakingContractAddress, } if bi.UnlockedAt != maxBlockNumber { vb.StakeBlockHeight = bi.UnlockedAt diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index c90b675c97..f1b104e72d 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1385,6 +1385,7 @@ func TestLiquidStaking(t *testing.T) { r.True(bt.UnstakeBlockHeight == math.MaxUint64) r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) + r.EqualValues(contractAddresses, bt.ContractAddress) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) From 0133dadb29378d3dc6ef49ddb97d203d87859711 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 19:52:39 +0800 Subject: [PATCH 45/51] add BucketsByCandidate --- blockindex/liquidstaking_cache.go | 18 ++++++++++++++++++ blockindex/liquidstaking_indexer.go | 17 +++++++++++++++++ e2etest/liquid_staking_test.go | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index 28ab0e2b5b..fd6f1ebf3f 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -27,6 +27,7 @@ type ( getAllBucketInfo() map[uint64]*ContractStakingBucketInfo getActiveBucketType() map[uint64]*ContractStakingBucketType getCandidateVotes(candidate address.Address) *big.Int + getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo } // liquidStakingCacheManager is the interface to manage liquid staking cache @@ -193,6 +194,16 @@ func (s *liquidStakingCache) getActiveBucketType() map[uint64]*ContractStakingBu return m } +func (s *liquidStakingCache) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { + m := make(map[uint64]*ContractStakingBucketInfo) + for k, v := range s.candidateBucketMap[candidate.String()] { + if v { + m[k] = s.idBucketMap[k] + } + } + return m +} + func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { for id, state := range delta.bucketTypeDeltaState { if state == deltaStateAdded || state == deltaStateModified { @@ -322,6 +333,13 @@ func (s *liquidStakingCacheThreadSafety) getActiveBucketType() map[uint64]*Contr return s.cache.getActiveBucketType() } +func (s *liquidStakingCacheThreadSafety) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { + s.mutex.RLock() + defer s.mutex.RUnlock() + + return s.cache.getBucketInfoByCandidate(candidate) +} + func (s *liquidStakingCacheThreadSafety) merge(delta *liquidStakingDelta) error { s.mutex.Lock() defer s.mutex.Unlock() diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 03098ef682..703a97e4ff 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -386,6 +386,8 @@ type ( Bucket(id uint64) (*ContractStakingBucket, error) // BucketsByIndices returns buckets by indices BucketsByIndices(indices []uint64) ([]*ContractStakingBucket, error) + // BucketsByCandidate returns buckets by candidate + BucketsByCandidate(candidate address.Address) ([]*ContractStakingBucket, error) // TotalBucketCount returns the total bucket count including burned buckets TotalBucketCount() uint64 // ActiveBucketTypes returns all active bucket types @@ -536,6 +538,21 @@ func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*ContractSt return vbs, nil } +func (s *liquidStakingIndexer) BucketsByCandidate(candidate address.Address) ([]*ContractStakingBucket, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + vbs := make([]*ContractStakingBucket, 0) + for id := range s.cache.getBucketInfoByCandidate(candidate) { + vb, err := s.generateBucket(id) + if err != nil { + return nil, err + } + vbs = append(vbs, vb) + } + return vbs, nil +} + func (s *liquidStakingIndexer) TotalBucketCount() uint64 { return s.cache.getTotalBucketCount() } diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index f1b104e72d..58dd7f0e2b 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -1386,6 +1386,10 @@ func TestLiquidStaking(t *testing.T) { r.EqualValues(10, indexer.CandidateVotes(identityset.Address(delegateIdx)).Int64()) r.EqualValues(1, indexer.TotalBucketCount()) r.EqualValues(contractAddresses, bt.ContractAddress) + buckets, err = indexer.BucketsByCandidate(identityset.Address(delegateIdx)) + r.NoError(err) + r.Len(buckets, 1) + r.EqualValues(bt, buckets[0]) t.Run("unlock", func(t *testing.T) { data, err = lsdABI.Pack("unlock0", big.NewInt(int64(bt.Index))) From dc1ee1ed2e60fd217b6af116f2c9f206f022f008 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 20:08:25 +0800 Subject: [PATCH 46/51] rename liquidstaking to contractstaking --- ...ket.pb.go => contractstaking_bucket.pb.go} | 116 +++++++++--------- ...ket.proto => contractstaking_bucket.proto} | 0 blockindex/liquidstaking_cache.go | 98 +++++++-------- blockindex/liquidstaking_cache_test.go | 4 +- blockindex/liquidstaking_delta.go | 40 +++--- blockindex/liquidstaking_dirty.go | 78 ++++++------ blockindex/liquidstaking_indexer.go | 96 +++++++-------- chainservice/builder.go | 6 +- e2etest/liquid_staking_test.go | 30 ++--- 9 files changed, 234 insertions(+), 234 deletions(-) rename blockindex/indexpb/{liquidstaking_bucket.pb.go => contractstaking_bucket.pb.go} (52%) rename blockindex/indexpb/{liquidstaking_bucket.proto => contractstaking_bucket.proto} (100%) diff --git a/blockindex/indexpb/liquidstaking_bucket.pb.go b/blockindex/indexpb/contractstaking_bucket.pb.go similarity index 52% rename from blockindex/indexpb/liquidstaking_bucket.pb.go rename to blockindex/indexpb/contractstaking_bucket.pb.go index 1bb3d5b164..e5b4635118 100644 --- a/blockindex/indexpb/liquidstaking_bucket.pb.go +++ b/blockindex/indexpb/contractstaking_bucket.pb.go @@ -10,7 +10,7 @@ // versions: // protoc-gen-go v1.26.0 // protoc v3.21.12 -// source: blockindex/indexpb/liquidstaking_bucket.proto +// source: blockindex/indexpb/contractstaking_bucket.proto package indexpb @@ -41,7 +41,7 @@ type BucketType struct { func (x *BucketType) Reset() { *x = BucketType{} if protoimpl.UnsafeEnabled { - mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0] + mi := &file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -54,7 +54,7 @@ func (x *BucketType) String() string { func (*BucketType) ProtoMessage() {} func (x *BucketType) ProtoReflect() protoreflect.Message { - mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0] + mi := &file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -67,7 +67,7 @@ func (x *BucketType) ProtoReflect() protoreflect.Message { // Deprecated: Use BucketType.ProtoReflect.Descriptor instead. func (*BucketType) Descriptor() ([]byte, []int) { - return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP(), []int{0} + return file_blockindex_indexpb_contractstaking_bucket_proto_rawDescGZIP(), []int{0} } func (x *BucketType) GetAmount() string { @@ -107,7 +107,7 @@ type BucketInfo struct { func (x *BucketInfo) Reset() { *x = BucketInfo{} if protoimpl.UnsafeEnabled { - mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1] + mi := &file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -120,7 +120,7 @@ func (x *BucketInfo) String() string { func (*BucketInfo) ProtoMessage() {} func (x *BucketInfo) ProtoReflect() protoreflect.Message { - mi := &file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1] + mi := &file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -133,7 +133,7 @@ func (x *BucketInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use BucketInfo.ProtoReflect.Descriptor instead. func (*BucketInfo) Descriptor() ([]byte, []int) { - return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP(), []int{1} + return file_blockindex_indexpb_contractstaking_bucket_proto_rawDescGZIP(), []int{1} } func (x *BucketInfo) GetTypeIndex() uint64 { @@ -178,55 +178,55 @@ func (x *BucketInfo) GetOwner() string { return "" } -var File_blockindex_indexpb_liquidstaking_bucket_proto protoreflect.FileDescriptor - -var file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = []byte{ - 0x0a, 0x2d, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x70, 0x62, 0x2f, 0x6c, 0x69, 0x71, 0x75, 0x69, 0x64, 0x73, 0x74, 0x61, 0x6b, 0x69, - 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x22, 0x62, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, - 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x63, - 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xba, 0x01, 0x0a, - 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74, - 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, - 0x74, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, 0x6f, 0x63, - 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x6c, - 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x73, 0x74, 0x61, - 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x6e, 0x73, - 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +var File_blockindex_indexpb_contractstaking_bucket_proto protoreflect.FileDescriptor + +var file_blockindex_indexpb_contractstaking_bucket_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x74, 0x61, + 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x70, 0x62, 0x22, 0x62, 0x0a, 0x0a, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xba, + 0x01, 0x0a, 0x0a, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x74, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x6c, + 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, + 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x73, + 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, + 0x6e, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x37, 0x5a, 0x35, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2f, 0x69, 0x6f, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, + 0x65, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescOnce sync.Once - file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData = file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc + file_blockindex_indexpb_contractstaking_bucket_proto_rawDescOnce sync.Once + file_blockindex_indexpb_contractstaking_bucket_proto_rawDescData = file_blockindex_indexpb_contractstaking_bucket_proto_rawDesc ) -func file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescGZIP() []byte { - file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescOnce.Do(func() { - file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData = protoimpl.X.CompressGZIP(file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData) +func file_blockindex_indexpb_contractstaking_bucket_proto_rawDescGZIP() []byte { + file_blockindex_indexpb_contractstaking_bucket_proto_rawDescOnce.Do(func() { + file_blockindex_indexpb_contractstaking_bucket_proto_rawDescData = protoimpl.X.CompressGZIP(file_blockindex_indexpb_contractstaking_bucket_proto_rawDescData) }) - return file_blockindex_indexpb_liquidstaking_bucket_proto_rawDescData + return file_blockindex_indexpb_contractstaking_bucket_proto_rawDescData } -var file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = []interface{}{ +var file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_blockindex_indexpb_contractstaking_bucket_proto_goTypes = []interface{}{ (*BucketType)(nil), // 0: indexpb.BucketType (*BucketInfo)(nil), // 1: indexpb.BucketInfo } -var file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = []int32{ +var file_blockindex_indexpb_contractstaking_bucket_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name @@ -234,13 +234,13 @@ var file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for field type_name } -func init() { file_blockindex_indexpb_liquidstaking_bucket_proto_init() } -func file_blockindex_indexpb_liquidstaking_bucket_proto_init() { - if File_blockindex_indexpb_liquidstaking_bucket_proto != nil { +func init() { file_blockindex_indexpb_contractstaking_bucket_proto_init() } +func file_blockindex_indexpb_contractstaking_bucket_proto_init() { + if File_blockindex_indexpb_contractstaking_bucket_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BucketType); i { case 0: return &v.state @@ -252,7 +252,7 @@ func file_blockindex_indexpb_liquidstaking_bucket_proto_init() { return nil } } - file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BucketInfo); i { case 0: return &v.state @@ -269,18 +269,18 @@ func file_blockindex_indexpb_liquidstaking_bucket_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc, + RawDescriptor: file_blockindex_indexpb_contractstaking_bucket_proto_rawDesc, NumEnums: 0, NumMessages: 2, NumExtensions: 0, NumServices: 0, }, - GoTypes: file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes, - DependencyIndexes: file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs, - MessageInfos: file_blockindex_indexpb_liquidstaking_bucket_proto_msgTypes, + GoTypes: file_blockindex_indexpb_contractstaking_bucket_proto_goTypes, + DependencyIndexes: file_blockindex_indexpb_contractstaking_bucket_proto_depIdxs, + MessageInfos: file_blockindex_indexpb_contractstaking_bucket_proto_msgTypes, }.Build() - File_blockindex_indexpb_liquidstaking_bucket_proto = out.File - file_blockindex_indexpb_liquidstaking_bucket_proto_rawDesc = nil - file_blockindex_indexpb_liquidstaking_bucket_proto_goTypes = nil - file_blockindex_indexpb_liquidstaking_bucket_proto_depIdxs = nil + File_blockindex_indexpb_contractstaking_bucket_proto = out.File + file_blockindex_indexpb_contractstaking_bucket_proto_rawDesc = nil + file_blockindex_indexpb_contractstaking_bucket_proto_goTypes = nil + file_blockindex_indexpb_contractstaking_bucket_proto_depIdxs = nil } diff --git a/blockindex/indexpb/liquidstaking_bucket.proto b/blockindex/indexpb/contractstaking_bucket.proto similarity index 100% rename from blockindex/indexpb/liquidstaking_bucket.proto rename to blockindex/indexpb/contractstaking_bucket.proto diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index fd6f1ebf3f..c570f56985 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -13,9 +13,9 @@ import ( ) type ( - // liquidStakingCacheReader is the interface to read liquid staking cache + // contractStakingCacheReader is the interface to read contract staking cache // it serves the purpose of preventing modifications to it. - liquidStakingCacheReader interface { + contractStakingCacheReader interface { getHeight() uint64 getTotalBucketCount() uint64 getTotalBucketTypeCount() uint64 @@ -30,11 +30,11 @@ type ( getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo } - // liquidStakingCacheManager is the interface to manage liquid staking cache + // contractStakingCacheManager is the interface to manage contract staking cache // it's used to hide internal data, ensuring thread safety when used within the package - liquidStakingCacheManager interface { - liquidStakingCacheReader - merge(delta *liquidStakingDelta) error + contractStakingCacheManager interface { + contractStakingCacheReader + merge(delta *contractStakingDelta) error putHeight(h uint64) putTotalBucketCount(cnt uint64) putBucketType(id uint64, bt *ContractStakingBucketType) @@ -42,7 +42,7 @@ type ( deleteBucketInfo(id uint64) } - liquidStakingCache struct { + contractStakingCache struct { idBucketMap map[uint64]*ContractStakingBucketInfo // map[token]BucketInfo candidateBucketMap map[string]map[uint64]bool // map[candidate]bucket idBucketTypeMap map[uint64]*ContractStakingBucketType // map[token]BucketType @@ -51,31 +51,31 @@ type ( totalBucketCount uint64 // total number of buckets including burned buckets } - liquidStakingCacheThreadSafety struct { - cache liquidStakingCacheManager + contractStakingCacheThreadSafety struct { + cache contractStakingCacheManager mutex sync.RWMutex } ) -func newLiquidStakingCache() *liquidStakingCacheThreadSafety { - cache := &liquidStakingCache{ +func newContractStakingCache() *contractStakingCacheThreadSafety { + cache := &contractStakingCache{ idBucketMap: make(map[uint64]*ContractStakingBucketInfo), idBucketTypeMap: make(map[uint64]*ContractStakingBucketType), propertyBucketTypeMap: make(map[int64]map[uint64]uint64), candidateBucketMap: make(map[string]map[uint64]bool), } - return &liquidStakingCacheThreadSafety{cache: cache} + return &contractStakingCacheThreadSafety{cache: cache} } -func (s *liquidStakingCache) putHeight(h uint64) { +func (s *contractStakingCache) putHeight(h uint64) { s.height = h } -func (s *liquidStakingCache) getHeight() uint64 { +func (s *contractStakingCache) getHeight() uint64 { return s.height } -func (s *liquidStakingCache) putBucketType(id uint64, bt *ContractStakingBucketType) { +func (s *contractStakingCache) putBucketType(id uint64, bt *ContractStakingBucketType) { amount := bt.Amount.Int64() s.idBucketTypeMap[id] = bt m, ok := s.propertyBucketTypeMap[amount] @@ -86,7 +86,7 @@ func (s *liquidStakingCache) putBucketType(id uint64, bt *ContractStakingBucketT m[bt.Duration] = id } -func (s *liquidStakingCache) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { +func (s *contractStakingCache) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { s.idBucketMap[id] = bi if _, ok := s.candidateBucketMap[bi.Delegate.String()]; !ok { s.candidateBucketMap[bi.Delegate.String()] = make(map[uint64]bool) @@ -94,7 +94,7 @@ func (s *liquidStakingCache) putBucketInfo(id uint64, bi *ContractStakingBucketI s.candidateBucketMap[bi.Delegate.String()][id] = true } -func (s *liquidStakingCache) deleteBucketInfo(id uint64) { +func (s *contractStakingCache) deleteBucketInfo(id uint64) { bi, ok := s.idBucketMap[id] if !ok { return @@ -106,7 +106,7 @@ func (s *liquidStakingCache) deleteBucketInfo(id uint64) { delete(s.candidateBucketMap[bi.Delegate.String()], id) } -func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { +func (s *contractStakingCache) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { m, ok := s.propertyBucketTypeMap[amount.Int64()] if !ok { return 0, false @@ -115,12 +115,12 @@ func (s *liquidStakingCache) getBucketTypeIndex(amount *big.Int, duration uint64 return id, ok } -func (s *liquidStakingCache) getBucketType(id uint64) (*ContractStakingBucketType, bool) { +func (s *contractStakingCache) getBucketType(id uint64) (*ContractStakingBucketType, bool) { bt, ok := s.idBucketTypeMap[id] return bt, ok } -func (s *liquidStakingCache) mustGetBucketType(id uint64) *ContractStakingBucketType { +func (s *contractStakingCache) mustGetBucketType(id uint64) *ContractStakingBucketType { bt, ok := s.idBucketTypeMap[id] if !ok { panic("bucket type not found") @@ -128,12 +128,12 @@ func (s *liquidStakingCache) mustGetBucketType(id uint64) *ContractStakingBucket return bt } -func (s *liquidStakingCache) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { +func (s *contractStakingCache) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { bi, ok := s.idBucketMap[id] return bi, ok } -func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { +func (s *contractStakingCache) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { bt, ok := s.idBucketMap[id] if !ok { panic("bucket info not found") @@ -141,7 +141,7 @@ func (s *liquidStakingCache) mustGetBucketInfo(id uint64) *ContractStakingBucket return bt } -func (s *liquidStakingCache) getCandidateVotes(candidate address.Address) *big.Int { +func (s *contractStakingCache) getCandidateVotes(candidate address.Address) *big.Int { votes := big.NewInt(0) m, ok := s.candidateBucketMap[candidate.String()] if !ok { @@ -164,19 +164,19 @@ func (s *liquidStakingCache) getCandidateVotes(candidate address.Address) *big.I return votes } -func (s *liquidStakingCache) putTotalBucketCount(count uint64) { +func (s *contractStakingCache) putTotalBucketCount(count uint64) { s.totalBucketCount = count } -func (s *liquidStakingCache) getTotalBucketCount() uint64 { +func (s *contractStakingCache) getTotalBucketCount() uint64 { return s.totalBucketCount } -func (s *liquidStakingCache) getTotalBucketTypeCount() uint64 { +func (s *contractStakingCache) getTotalBucketTypeCount() uint64 { return uint64(len(s.idBucketTypeMap)) } -func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { +func (s *contractStakingCache) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { m := make(map[uint64]*ContractStakingBucketInfo) for k, v := range s.idBucketMap { m[k] = v @@ -184,7 +184,7 @@ func (s *liquidStakingCache) getAllBucketInfo() map[uint64]*ContractStakingBucke return m } -func (s *liquidStakingCache) getActiveBucketType() map[uint64]*ContractStakingBucketType { +func (s *contractStakingCache) getActiveBucketType() map[uint64]*ContractStakingBucketType { m := make(map[uint64]*ContractStakingBucketType) for k, v := range s.idBucketTypeMap { if v.ActivatedAt != maxBlockNumber { @@ -194,7 +194,7 @@ func (s *liquidStakingCache) getActiveBucketType() map[uint64]*ContractStakingBu return m } -func (s *liquidStakingCache) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { +func (s *contractStakingCache) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { m := make(map[uint64]*ContractStakingBucketInfo) for k, v := range s.candidateBucketMap[candidate.String()] { if v { @@ -204,7 +204,7 @@ func (s *liquidStakingCache) getBucketInfoByCandidate(candidate address.Address) return m } -func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { +func (s *contractStakingCache) merge(delta *contractStakingDelta) error { for id, state := range delta.bucketTypeDeltaState { if state == deltaStateAdded || state == deltaStateModified { s.putBucketType(id, delta.mustGetBucketType(id)) @@ -222,131 +222,131 @@ func (s *liquidStakingCache) merge(delta *liquidStakingDelta) error { return nil } -func (s *liquidStakingCacheThreadSafety) putHeight(h uint64) { +func (s *contractStakingCacheThreadSafety) putHeight(h uint64) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.putHeight(h) } -func (s *liquidStakingCacheThreadSafety) getHeight() uint64 { +func (s *contractStakingCacheThreadSafety) getHeight() uint64 { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getHeight() } -func (s *liquidStakingCacheThreadSafety) putBucketType(id uint64, bt *ContractStakingBucketType) { +func (s *contractStakingCacheThreadSafety) putBucketType(id uint64, bt *ContractStakingBucketType) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.putBucketType(id, bt) } -func (s *liquidStakingCacheThreadSafety) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { +func (s *contractStakingCacheThreadSafety) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.putBucketInfo(id, bi) } -func (s *liquidStakingCacheThreadSafety) deleteBucketInfo(id uint64) { +func (s *contractStakingCacheThreadSafety) deleteBucketInfo(id uint64) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.deleteBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { +func (s *contractStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketTypeIndex(amount, duration) } -func (s *liquidStakingCacheThreadSafety) getBucketType(id uint64) (*ContractStakingBucketType, bool) { +func (s *contractStakingCacheThreadSafety) getBucketType(id uint64) (*ContractStakingBucketType, bool) { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketType(id) } -func (s *liquidStakingCacheThreadSafety) mustGetBucketType(id uint64) *ContractStakingBucketType { +func (s *contractStakingCacheThreadSafety) mustGetBucketType(id uint64) *ContractStakingBucketType { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.mustGetBucketType(id) } -func (s *liquidStakingCacheThreadSafety) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { +func (s *contractStakingCacheThreadSafety) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { +func (s *contractStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.mustGetBucketInfo(id) } -func (s *liquidStakingCacheThreadSafety) getCandidateVotes(candidate address.Address) *big.Int { +func (s *contractStakingCacheThreadSafety) getCandidateVotes(candidate address.Address) *big.Int { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getCandidateVotes(candidate) } -func (s *liquidStakingCacheThreadSafety) putTotalBucketCount(count uint64) { +func (s *contractStakingCacheThreadSafety) putTotalBucketCount(count uint64) { s.mutex.Lock() defer s.mutex.Unlock() s.cache.putTotalBucketCount(count) } -func (s *liquidStakingCacheThreadSafety) getTotalBucketCount() uint64 { +func (s *contractStakingCacheThreadSafety) getTotalBucketCount() uint64 { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getTotalBucketCount() } -func (s *liquidStakingCacheThreadSafety) getTotalBucketTypeCount() uint64 { +func (s *contractStakingCacheThreadSafety) getTotalBucketTypeCount() uint64 { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getTotalBucketTypeCount() } -func (s *liquidStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { +func (s *contractStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getAllBucketInfo() } -func (s *liquidStakingCacheThreadSafety) getActiveBucketType() map[uint64]*ContractStakingBucketType { +func (s *contractStakingCacheThreadSafety) getActiveBucketType() map[uint64]*ContractStakingBucketType { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getActiveBucketType() } -func (s *liquidStakingCacheThreadSafety) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { +func (s *contractStakingCacheThreadSafety) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { s.mutex.RLock() defer s.mutex.RUnlock() return s.cache.getBucketInfoByCandidate(candidate) } -func (s *liquidStakingCacheThreadSafety) merge(delta *liquidStakingDelta) error { +func (s *contractStakingCacheThreadSafety) merge(delta *contractStakingDelta) error { s.mutex.Lock() defer s.mutex.Unlock() return s.cache.merge(delta) } -func (s *liquidStakingCacheThreadSafety) unsafe() liquidStakingCacheManager { +func (s *contractStakingCacheThreadSafety) unsafe() contractStakingCacheManager { return s.cache } diff --git a/blockindex/liquidstaking_cache_test.go b/blockindex/liquidstaking_cache_test.go index f4d2637cd5..1872f7debd 100644 --- a/blockindex/liquidstaking_cache_test.go +++ b/blockindex/liquidstaking_cache_test.go @@ -11,8 +11,8 @@ import ( "testing" ) -func TestLiquidStakingCacheThreadSafety(t *testing.T) { - cache := newLiquidStakingCache() +func TestContractStakingCacheThreadSafety(t *testing.T) { + cache := newContractStakingCache() wait := sync.WaitGroup{} wait.Add(2) diff --git a/blockindex/liquidstaking_delta.go b/blockindex/liquidstaking_delta.go index c13acb2b57..37d95641dd 100644 --- a/blockindex/liquidstaking_delta.go +++ b/blockindex/liquidstaking_delta.go @@ -22,8 +22,8 @@ type ( deltaState int deltaAction int - liquidStakingDelta struct { - liquidStakingCacheManager // easy to query buckets + contractStakingDelta struct { + contractStakingCacheManager // easy to query buckets bucketTypeDeltaState map[uint64]deltaState bucketInfoDeltaState map[uint64]deltaState @@ -59,15 +59,15 @@ func (s deltaState) transfer(act deltaAction) (deltaState, error) { return deltaStateTransferMap[s][act], nil } -func newLiquidStakingDelta() *liquidStakingDelta { - return &liquidStakingDelta{ - liquidStakingCacheManager: newLiquidStakingCache(), - bucketTypeDeltaState: make(map[uint64]deltaState), - bucketInfoDeltaState: make(map[uint64]deltaState), +func newContractStakingDelta() *contractStakingDelta { + return &contractStakingDelta{ + contractStakingCacheManager: newContractStakingCache(), + bucketTypeDeltaState: make(map[uint64]deltaState), + bucketInfoDeltaState: make(map[uint64]deltaState), } } -func (s *liquidStakingDelta) addBucketType(id uint64, bt *ContractStakingBucketType) error { +func (s *contractStakingDelta) addBucketType(id uint64, bt *ContractStakingBucketType) error { if _, ok := s.bucketTypeDeltaState[id]; !ok { s.bucketTypeDeltaState[id] = deltaStateAdded } else { @@ -77,11 +77,11 @@ func (s *liquidStakingDelta) addBucketType(id uint64, bt *ContractStakingBucketT return err } } - s.liquidStakingCacheManager.putBucketType(id, bt) + s.contractStakingCacheManager.putBucketType(id, bt) return nil } -func (s *liquidStakingDelta) updateBucketType(id uint64, bt *ContractStakingBucketType) error { +func (s *contractStakingDelta) updateBucketType(id uint64, bt *ContractStakingBucketType) error { if _, ok := s.bucketTypeDeltaState[id]; !ok { s.bucketTypeDeltaState[id] = deltaStateModified } else { @@ -91,11 +91,11 @@ func (s *liquidStakingDelta) updateBucketType(id uint64, bt *ContractStakingBuck return err } } - s.liquidStakingCacheManager.putBucketType(id, bt) + s.contractStakingCacheManager.putBucketType(id, bt) return nil } -func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { +func (s *contractStakingDelta) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { var err error if _, ok := s.bucketInfoDeltaState[id]; !ok { s.bucketInfoDeltaState[id] = deltaStateAdded @@ -105,11 +105,11 @@ func (s *liquidStakingDelta) addBucketInfo(id uint64, bi *ContractStakingBucketI return err } } - s.liquidStakingCacheManager.putBucketInfo(id, bi) + s.contractStakingCacheManager.putBucketInfo(id, bi) return nil } -func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { +func (s *contractStakingDelta) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { if _, ok := s.bucketInfoDeltaState[id]; !ok { s.bucketInfoDeltaState[id] = deltaStateModified } else { @@ -119,11 +119,11 @@ func (s *liquidStakingDelta) updateBucketInfo(id uint64, bi *ContractStakingBuck return err } } - s.liquidStakingCacheManager.putBucketInfo(id, bi) + s.contractStakingCacheManager.putBucketInfo(id, bi) return nil } -func (s *liquidStakingDelta) deleteBucketInfo(id uint64) error { +func (s *contractStakingDelta) deleteBucketInfo(id uint64) error { if _, ok := s.bucketInfoDeltaState[id]; !ok { s.bucketInfoDeltaState[id] = deltaStateRemoved } else { @@ -133,11 +133,11 @@ func (s *liquidStakingDelta) deleteBucketInfo(id uint64) error { return err } } - s.liquidStakingCacheManager.deleteBucketInfo(id) + s.contractStakingCacheManager.deleteBucketInfo(id) return nil } -func (s *liquidStakingDelta) addedBucketCnt() uint64 { +func (s *contractStakingDelta) addedBucketCnt() uint64 { addedBucketCnt := uint64(0) for _, state := range s.bucketInfoDeltaState { if state == deltaStateAdded { @@ -147,7 +147,7 @@ func (s *liquidStakingDelta) addedBucketCnt() uint64 { return addedBucketCnt } -func (s *liquidStakingDelta) addedBucketTypeCnt() uint64 { +func (s *contractStakingDelta) addedBucketTypeCnt() uint64 { cnt := uint64(0) for _, state := range s.bucketTypeDeltaState { if state == deltaStateAdded { @@ -157,7 +157,7 @@ func (s *liquidStakingDelta) addedBucketTypeCnt() uint64 { return cnt } -func (s *liquidStakingDelta) isBucketDeleted(id uint64) bool { +func (s *contractStakingDelta) isBucketDeleted(id uint64) bool { if _, ok := s.bucketInfoDeltaState[id]; ok { return s.bucketInfoDeltaState[id] == deltaStateRemoved } diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 65fc2e4f13..26e40f96f5 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -17,60 +17,60 @@ import ( ) type ( - // liquidStakingDirty is the dirty data of liquid staking + // contractStakingDirty is the dirty data of contract staking // main functions: // 1. update bucket // 2. get up-to-date bucket // 3. store delta to merge to clean cache - liquidStakingDirty struct { - clean liquidStakingCacheReader // clean cache to get buckets of last block - delta *liquidStakingDelta // delta for cache to store buckets of current block - batch batch.KVStoreBatch // batch for db to store buckets of current block + contractStakingDirty struct { + clean contractStakingCacheReader // clean cache to get buckets of last block + delta *contractStakingDelta // delta for cache to store buckets of current block + batch batch.KVStoreBatch // batch for db to store buckets of current block tokenOwner map[uint64]address.Address once sync.Once } ) -func newLiquidStakingDirty(clean liquidStakingCacheReader) *liquidStakingDirty { - return &liquidStakingDirty{ +func newContractStakingDirty(clean contractStakingCacheReader) *contractStakingDirty { + return &contractStakingDirty{ clean: clean, - delta: newLiquidStakingDelta(), + delta: newContractStakingDelta(), batch: batch.NewBatch(), tokenOwner: make(map[uint64]address.Address), } } -func (dirty *liquidStakingDirty) putHeight(h uint64) { - dirty.batch.Put(_liquidStakingNS, _liquidStakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") +func (dirty *contractStakingDirty) putHeight(h uint64) { + dirty.batch.Put(_StakingNS, _stakingHeightKey, byteutil.Uint64ToBytesBigEndian(h), "failed to put height") dirty.delta.putHeight(h) } -func (dirty *liquidStakingDirty) addBucketType(id uint64, bt *ContractStakingBucketType) error { - dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") +func (dirty *contractStakingDirty) addBucketType(id uint64, bt *ContractStakingBucketType) error { + dirty.batch.Put(_StakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") return dirty.delta.addBucketType(id, bt) } -func (dirty *liquidStakingDirty) updateBucketType(id uint64, bt *ContractStakingBucketType) error { - dirty.batch.Put(_liquidStakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") +func (dirty *contractStakingDirty) updateBucketType(id uint64, bt *ContractStakingBucketType) error { + dirty.batch.Put(_StakingBucketTypeNS, byteutil.Uint64ToBytesBigEndian(id), bt.serialize(), "failed to put bucket type") return dirty.delta.updateBucketType(id, bt) } -func (dirty *liquidStakingDirty) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { - dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") +func (dirty *contractStakingDirty) addBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { + dirty.batch.Put(_StakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") return dirty.delta.addBucketInfo(id, bi) } -func (dirty *liquidStakingDirty) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { - dirty.batch.Put(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") +func (dirty *contractStakingDirty) updateBucketInfo(id uint64, bi *ContractStakingBucketInfo) error { + dirty.batch.Put(_StakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), bi.serialize(), "failed to put bucket info") return dirty.delta.updateBucketInfo(id, bi) } -func (dirty *liquidStakingDirty) burnBucket(id uint64) error { - dirty.batch.Delete(_liquidStakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") +func (dirty *contractStakingDirty) burnBucket(id uint64) error { + dirty.batch.Delete(_StakingBucketInfoNS, byteutil.Uint64ToBytesBigEndian(id), "failed to delete bucket info") return dirty.delta.deleteBucketInfo(id) } -func (dirty *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { +func (dirty *contractStakingDirty) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { id, ok := dirty.delta.getBucketTypeIndex(amount, duration) if ok { return id, true @@ -79,11 +79,11 @@ func (dirty *liquidStakingDirty) getBucketTypeIndex(amount *big.Int, duration ui return id, ok } -func (dirty *liquidStakingDirty) getBucketTypeCount() uint64 { +func (dirty *contractStakingDirty) getBucketTypeCount() uint64 { return dirty.clean.getTotalBucketTypeCount() + dirty.delta.addedBucketTypeCnt() } -func (dirty *liquidStakingDirty) getBucketType(id uint64) (*ContractStakingBucketType, bool) { +func (dirty *contractStakingDirty) getBucketType(id uint64) (*ContractStakingBucketType, bool) { bt, ok := dirty.delta.getBucketType(id) if ok { return bt, true @@ -92,7 +92,7 @@ func (dirty *liquidStakingDirty) getBucketType(id uint64) (*ContractStakingBucke return bt, ok } -func (dirty *liquidStakingDirty) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { +func (dirty *contractStakingDirty) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { if dirty.delta.isBucketDeleted(id) { return nil, false } @@ -104,19 +104,19 @@ func (dirty *liquidStakingDirty) getBucketInfo(id uint64) (*ContractStakingBucke return bi, ok } -func (dirty *liquidStakingDirty) finalizeBatch() batch.KVStoreBatch { +func (dirty *contractStakingDirty) finalizeBatch() batch.KVStoreBatch { dirty.once.Do(func() { total := dirty.clean.getTotalBucketCount() + dirty.delta.addedBucketCnt() - dirty.batch.Put(_liquidStakingNS, _liquidStakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(total), "failed to put total bucket count") + dirty.batch.Put(_StakingNS, _stakingTotalBucketCountKey, byteutil.Uint64ToBytesBigEndian(total), "failed to put total bucket count") }) return dirty.batch } -func (dirty *liquidStakingDirty) finalize() (batch.KVStoreBatch, *liquidStakingDelta) { +func (dirty *contractStakingDirty) finalize() (batch.KVStoreBatch, *contractStakingDelta) { return dirty.finalizeBatch(), dirty.delta } -func (dirty *liquidStakingDirty) handleTransferEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleTransferEvent(event eventParam) error { to, err := event.indexedFieldAddress("to") if err != nil { return err @@ -130,7 +130,7 @@ func (dirty *liquidStakingDirty) handleTransferEvent(event eventParam) error { return nil } -func (dirty *liquidStakingDirty) handleBucketTypeActivatedEvent(event eventParam, height uint64) error { +func (dirty *contractStakingDirty) handleBucketTypeActivatedEvent(event eventParam, height uint64) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -156,7 +156,7 @@ func (dirty *liquidStakingDirty) handleBucketTypeActivatedEvent(event eventParam return err } -func (dirty *liquidStakingDirty) handleBucketTypeDeactivatedEvent(event eventParam, height uint64) error { +func (dirty *contractStakingDirty) handleBucketTypeDeactivatedEvent(event eventParam, height uint64) error { amountParam, err := event.fieldUint256("amount") if err != nil { return err @@ -178,7 +178,7 @@ func (dirty *liquidStakingDirty) handleBucketTypeDeactivatedEvent(event eventPar return dirty.updateBucketType(id, bt) } -func (dirty *liquidStakingDirty) handleStakedEvent(event eventParam, height uint64) error { +func (dirty *contractStakingDirty) handleStakedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -211,7 +211,7 @@ func (dirty *liquidStakingDirty) handleStakedEvent(event eventParam, height uint return dirty.addBucketInfo(tokenIDParam.Uint64(), &bucket) } -func (dirty *liquidStakingDirty) handleLockedEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleLockedEvent(event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -238,7 +238,7 @@ func (dirty *liquidStakingDirty) handleLockedEvent(event eventParam) error { return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleUnlockedEvent(event eventParam, height uint64) error { +func (dirty *contractStakingDirty) handleUnlockedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -252,7 +252,7 @@ func (dirty *liquidStakingDirty) handleUnlockedEvent(event eventParam, height ui return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleUnstakedEvent(event eventParam, height uint64) error { +func (dirty *contractStakingDirty) handleUnstakedEvent(event eventParam, height uint64) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -266,7 +266,7 @@ func (dirty *liquidStakingDirty) handleUnstakedEvent(event eventParam, height ui return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleMergedEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleMergedEvent(event eventParam) error { tokenIDsParam, err := event.fieldUint256Slice("tokenIds") if err != nil { return err @@ -299,7 +299,7 @@ func (dirty *liquidStakingDirty) handleMergedEvent(event eventParam) error { return dirty.updateBucketInfo(tokenIDsParam[0].Uint64(), b) } -func (dirty *liquidStakingDirty) handleDurationExtendedEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleDurationExtendedEvent(event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -325,7 +325,7 @@ func (dirty *liquidStakingDirty) handleDurationExtendedEvent(event eventParam) e return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleAmountIncreasedEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleAmountIncreasedEvent(event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -351,7 +351,7 @@ func (dirty *liquidStakingDirty) handleAmountIncreasedEvent(event eventParam) er return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleDelegateChangedEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleDelegateChangedEvent(event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err @@ -369,7 +369,7 @@ func (dirty *liquidStakingDirty) handleDelegateChangedEvent(event eventParam) er return dirty.updateBucketInfo(tokenIDParam.Uint64(), b) } -func (dirty *liquidStakingDirty) handleWithdrawalEvent(event eventParam) error { +func (dirty *contractStakingDirty) handleWithdrawalEvent(event eventParam) error { tokenIDParam, err := event.indexedFieldUint256("tokenId") if err != nil { return err diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 703a97e4ff..832a95109d 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -25,11 +25,11 @@ import ( ) const ( - // LiquidStakingContractAddress is the address of liquid staking contract - // TODO (iip-13): replace with the real liquid staking contract address - LiquidStakingContractAddress = "io19ys8f4uhwms6lq6ulexr5fwht9gsjes8mvuugd" - // LiquidStakingContractABI is the ABI of liquid staking contract - LiquidStakingContractABI = `[ + // StakingContractAddress is the address of system staking contract + // TODO (iip-13): replace with the real system staking contract address + StakingContractAddress = "io19ys8f4uhwms6lq6ulexr5fwht9gsjes8mvuugd" + // StakingContractABI is the ABI of system staking contract + StakingContractABI = `[ { "anonymous": false, "inputs": [ @@ -368,9 +368,9 @@ const ( ]` // bucket related namespace in db - _liquidStakingBucketInfoNS = "lsbInfo" - _liquidStakingBucketTypeNS = "lsbType" - _liquidStakingNS = "lsns" + _StakingBucketInfoNS = "sbi" + _StakingBucketTypeNS = "sbt" + _StakingNS = "s" ) type ( @@ -394,27 +394,27 @@ type ( ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) } - // liquidStakingIndexer is the implementation of ContractStakingIndexer + // contractStakingIndexer is the implementation of ContractStakingIndexer // Main functions: - // 1. handle liquid staking contract events when new block comes to generate index data - // 2. provide query interface for liquid staking index data + // 1. handle contract staking contract events when new block comes to generate index data + // 2. provide query interface for contract staking index data // Generate index data flow: // block comes -> new dirty cache -> handle contract events -> update dirty cache -> merge dirty to clean cache // Main Object: // kvstore: persistent storage, used to initialize index cache at startup // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. - liquidStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *liquidStakingCacheThreadSafety // in-memory index for clean data - mutex sync.RWMutex // mutex for multiple reading to cache + contractStakingIndexer struct { + kvstore db.KVStore // persistent storage + cache *contractStakingCacheThreadSafety // in-memory index for clean data + mutex sync.RWMutex // mutex for multiple reading to cache } ) var ( - _liquidStakingInterface abi.ABI - _liquidStakingHeightKey = []byte("lsHeight") - _liquidStakingTotalBucketCountKey = []byte("lsTotalBucketCount") + _stakingInterface abi.ABI + _stakingHeightKey = []byte("shk") + _stakingTotalBucketCountKey = []byte("stbck") errBucketTypeNotExist = errors.New("bucket type does not exist") @@ -424,7 +424,7 @@ var ( func init() { var err error - _liquidStakingInterface, err = abi.JSON(strings.NewReader(LiquidStakingContractABI)) + _stakingInterface, err = abi.JSON(strings.NewReader(StakingContractABI)) if err != nil { panic(err) } @@ -432,14 +432,14 @@ func init() { // NewContractStakingIndexer creates a new contract staking indexer func NewContractStakingIndexer(kvStore db.KVStore) ContractStakingIndexer { - return &liquidStakingIndexer{ + return &contractStakingIndexer{ kvstore: kvStore, - cache: newLiquidStakingCache(), + cache: newContractStakingCache(), } } // Start starts the indexer -func (s *liquidStakingIndexer) Start(ctx context.Context) error { +func (s *contractStakingIndexer) Start(ctx context.Context) error { if err := s.kvstore.Start(ctx); err != nil { return err } @@ -447,20 +447,20 @@ func (s *liquidStakingIndexer) Start(ctx context.Context) error { } // Stop stops the indexer -func (s *liquidStakingIndexer) Stop(ctx context.Context) error { +func (s *contractStakingIndexer) Stop(ctx context.Context) error { if err := s.kvstore.Stop(ctx); err != nil { return err } - s.cache = newLiquidStakingCache() + s.cache = newContractStakingCache() return nil } // PutBlock puts a block into indexer -func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { +func (s *contractStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) error { // new dirty cache for this block // it's not necessary to use thread safe cache here, because only one thread will call this function // and no update to cache will happen before dirty merge to clean - dirty := newLiquidStakingDirty(s.cache.unsafe()) + dirty := newContractStakingDirty(s.cache.unsafe()) dirty.putHeight(blk.Height()) // handle events of block @@ -469,7 +469,7 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e continue } for _, log := range receipt.Logs() { - if log.Address != LiquidStakingContractAddress { + if log.Address != StakingContractAddress { continue } if err := s.handleEvent(ctx, dirty, blk, log); err != nil { @@ -483,22 +483,22 @@ func (s *liquidStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) e } // DeleteTipBlock deletes the tip block from indexer -func (s *liquidStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { +func (s *contractStakingIndexer) DeleteTipBlock(context.Context, *block.Block) error { return errors.New("not implemented") } // Height returns the tip block height -func (s *liquidStakingIndexer) Height() (uint64, error) { +func (s *contractStakingIndexer) Height() (uint64, error) { return s.cache.getHeight(), nil } // CandidateVotes returns the candidate votes -func (s *liquidStakingIndexer) CandidateVotes(candidate address.Address) *big.Int { +func (s *contractStakingIndexer) CandidateVotes(candidate address.Address) *big.Int { return s.cache.getCandidateVotes(candidate) } // Buckets returns the buckets -func (s *liquidStakingIndexer) Buckets() ([]*ContractStakingBucket, error) { +func (s *contractStakingIndexer) Buckets() ([]*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() @@ -515,7 +515,7 @@ func (s *liquidStakingIndexer) Buckets() ([]*ContractStakingBucket, error) { } // Bucket returns the bucket -func (s *liquidStakingIndexer) Bucket(id uint64) (*ContractStakingBucket, error) { +func (s *contractStakingIndexer) Bucket(id uint64) (*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() @@ -523,7 +523,7 @@ func (s *liquidStakingIndexer) Bucket(id uint64) (*ContractStakingBucket, error) } // BucketsByIndices returns the buckets by indices -func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*ContractStakingBucket, error) { +func (s *contractStakingIndexer) BucketsByIndices(indices []uint64) ([]*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() @@ -538,7 +538,7 @@ func (s *liquidStakingIndexer) BucketsByIndices(indices []uint64) ([]*ContractSt return vbs, nil } -func (s *liquidStakingIndexer) BucketsByCandidate(candidate address.Address) ([]*ContractStakingBucket, error) { +func (s *contractStakingIndexer) BucketsByCandidate(candidate address.Address) ([]*ContractStakingBucket, error) { s.mutex.RLock() defer s.mutex.RUnlock() @@ -553,15 +553,15 @@ func (s *liquidStakingIndexer) BucketsByCandidate(candidate address.Address) ([] return vbs, nil } -func (s *liquidStakingIndexer) TotalBucketCount() uint64 { +func (s *contractStakingIndexer) TotalBucketCount() uint64 { return s.cache.getTotalBucketCount() } -func (s *liquidStakingIndexer) ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) { +func (s *contractStakingIndexer) ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) { return s.cache.getActiveBucketType(), nil } -func (s *liquidStakingIndexer) generateBucket(id uint64) (*ContractStakingBucket, error) { +func (s *contractStakingIndexer) generateBucket(id uint64) (*ContractStakingBucket, error) { bi, ok := s.cache.getBucketInfo(id) if !ok { return nil, errors.Wrapf(ErrBucketInfoNotExist, "id %d", id) @@ -570,9 +570,9 @@ func (s *liquidStakingIndexer) generateBucket(id uint64) (*ContractStakingBucket return s.assembleContractStakingBucket(id, bi, bt) } -func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidStakingDirty, blk *block.Block, log *action.Log) error { +func (s *contractStakingIndexer) handleEvent(ctx context.Context, dirty *contractStakingDirty, blk *block.Block, log *action.Log) error { // get event abi - abiEvent, err := _liquidStakingInterface.EventByID(common.Hash(log.Topics[0])) + abiEvent, err := _stakingInterface.EventByID(common.Hash(log.Topics[0])) if err != nil { return errors.Wrapf(err, "get event abi from topic %v failed", log.Topics[0]) } @@ -614,11 +614,11 @@ func (s *liquidStakingIndexer) handleEvent(ctx context.Context, dirty *liquidSta } } -func (s *liquidStakingIndexer) loadCache() error { - delta := newLiquidStakingDelta() +func (s *contractStakingIndexer) loadCache() error { + delta := newContractStakingDelta() // load height var height uint64 - h, err := s.kvstore.Get(_liquidStakingNS, _liquidStakingHeightKey) + h, err := s.kvstore.Get(_StakingNS, _stakingHeightKey) if err != nil { if !errors.Is(err, db.ErrNotExist) { return err @@ -632,7 +632,7 @@ func (s *liquidStakingIndexer) loadCache() error { // load total bucket count var totalBucketCount uint64 - tbc, err := s.kvstore.Get(_liquidStakingNS, _liquidStakingTotalBucketCountKey) + tbc, err := s.kvstore.Get(_StakingNS, _stakingTotalBucketCountKey) if err != nil { if !errors.Is(err, db.ErrNotExist) { return err @@ -643,7 +643,7 @@ func (s *liquidStakingIndexer) loadCache() error { delta.putTotalBucketCount(totalBucketCount) // load bucket info - ks, vs, err := s.kvstore.Filter(_liquidStakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) + ks, vs, err := s.kvstore.Filter(_StakingBucketInfoNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil && !errors.Is(err, db.ErrBucketNotExist) { return err } @@ -656,7 +656,7 @@ func (s *liquidStakingIndexer) loadCache() error { } // load bucket type - ks, vs, err = s.kvstore.Filter(_liquidStakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) + ks, vs, err = s.kvstore.Filter(_StakingBucketTypeNS, func(k, v []byte) bool { return true }, nil, nil) if err != nil && !errors.Is(err, db.ErrBucketNotExist) { return err } @@ -670,7 +670,7 @@ func (s *liquidStakingIndexer) loadCache() error { return s.cache.merge(delta) } -func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { +func (s *contractStakingIndexer) commit(dirty *contractStakingDirty) error { s.mutex.Lock() defer s.mutex.Unlock() @@ -684,7 +684,7 @@ func (s *liquidStakingIndexer) commit(dirty *liquidStakingDirty) error { return nil } -func (s *liquidStakingIndexer) assembleContractStakingBucket(token uint64, bi *ContractStakingBucketInfo, bt *ContractStakingBucketType) (*ContractStakingBucket, error) { +func (s *contractStakingIndexer) assembleContractStakingBucket(token uint64, bi *ContractStakingBucketInfo, bt *ContractStakingBucketType) (*ContractStakingBucket, error) { vb := ContractStakingBucket{ Index: token, StakedAmount: bt.Amount, @@ -695,7 +695,7 @@ func (s *liquidStakingIndexer) assembleContractStakingBucket(token uint64, bi *C AutoStake: bi.UnlockedAt == maxBlockNumber, Candidate: bi.Delegate, Owner: bi.Owner, - ContractAddress: LiquidStakingContractAddress, + ContractAddress: StakingContractAddress, } if bi.UnlockedAt != maxBlockNumber { vb.StakeBlockHeight = bi.UnlockedAt diff --git a/chainservice/builder.go b/chainservice/builder.go index 228e920df9..5fb87cb876 100644 --- a/chainservice/builder.go +++ b/chainservice/builder.go @@ -488,8 +488,8 @@ func (builder *Builder) registerStakingProtocol() error { return nil } - // TODO (iip-13): use a real liquid indexer instead - liquidIndexer := staking.NewEmptyLiquidStakingIndexer() + // TODO (iip-13): use a real contract indexer instead + contractStakingIndexer := staking.NewEmptyLiquidStakingIndexer() stakingProtocol, err := staking.NewProtocol( rewarding.DepositGas, @@ -499,7 +499,7 @@ func (builder *Builder) registerStakingProtocol() error { StakingPatchDir: builder.cfg.Chain.StakingPatchDir, }, builder.cs.candBucketsIndexer, - liquidIndexer, + contractStakingIndexer, builder.cfg.Genesis.OkhotskBlockHeight, builder.cfg.Genesis.GreenlandBlockHeight, builder.cfg.Genesis.HawaiiBlockHeight, diff --git a/e2etest/liquid_staking_test.go b/e2etest/liquid_staking_test.go index 58dd7f0e2b..329b6409d9 100644 --- a/e2etest/liquid_staking_test.go +++ b/e2etest/liquid_staking_test.go @@ -37,9 +37,9 @@ import ( ) const ( - // _liquidStakingContractByteCode is the byte code of the liquid staking contract for testing, which changes the freeze blocks to 10 - _liquidStakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c80637acb77571161015a578063bbe33ea5116100c1578063e449f3411161007a578063e449f341146107e9578063e985e9c514610809578063eb0ffb2e14610852578063eec7ee7314610872578063f0b56b5d14610885578063f2fde38b1461089a57600080fd5b8063bbe33ea514610740578063c87b56dd14610753578063c8e7792314610773578063d0949f9914610793578063d6605fd8146107a9578063e0028ecf146107c957600080fd5b806398ca3b761161011357806398ca3b76146106985780639f7d5b00146106b8578063a22cb465146106cd578063b2383e55146106ed578063b88d4fde14610700578063b8f4bd7b1461072057600080fd5b80637acb7757146105fd5780638456cb59146106105780638da5cb5b1461062557806393b6ef591461064357806395d89b4114610663578063960014bd1461067857600080fd5b806342842e0e116101fe5780636198e339116101b75780636198e339146105485780636352211e1461056857806370a0823114610588578063711563d4146105a8578063715018a6146105bb57806378bfca10146105d057600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104c95780635c975abb146104e95780635ceb8b5b146105085780635d36598f1461052857600080fd5b80630f5b2ca5116102505780630f5b2ca5146103965780631338736f146103b657806323b872dd146103d65780632e17de78146103f65780633f4ba83a146104165780633fd140df1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b23660046134d2565b6108ba565b005b3480156102c557600080fd5b506102d96102d4366004613518565b610981565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613535565b6109d3565b6040519081526020016102e5565b34801561032857600080fd5b506103316109f9565b6040516102e5919061359e565b34801561034a57600080fd5b5061035e610359366004613535565b610a8b565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046135b1565b610ab2565b3480156103a257600080fd5b506102b76103b13660046134d2565b610bc7565b3480156103c257600080fd5b506102b76103d13660046135dd565b610c34565b3480156103e257600080fd5b506102b76103f13660046135ff565b610ca7565b34801561040257600080fd5b506102b7610411366004613535565b610cd8565b34801561042257600080fd5b506102b7610d87565b34801561043757600080fd5b5061044b61044636600461368b565b610d99565b6040516102e591906136cc565b34801561046457600080fd5b506102b76104733660046135ff565b610f1b565b34801561048457600080fd5b50610498610493366004613535565b610f36565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a0016102e5565b3480156104d557600080fd5b506102d96104e43660046135dd565b610fb2565b3480156104f557600080fd5b50600654600160a01b900460ff166102d9565b34801561051457600080fd5b506102b7610523366004613756565b610fcd565b34801561053457600080fd5b506102b761054336600461368b565b611074565b34801561055457600080fd5b506102b7610563366004613535565b61110a565b34801561057457600080fd5b5061035e610583366004613535565b61116c565b34801561059457600080fd5b5061030e6105a33660046137a1565b6111cc565b61030e6105b63660046137be565b611252565b3480156105c757600080fd5b506102b761132b565b3480156105dc57600080fd5b506105f06105eb3660046135dd565b61133d565b6040516102e591906137fd565b61030e61060b3660046134d2565b611472565b34801561061c57600080fd5b506102b76114f6565b34801561063157600080fd5b506006546001600160a01b031661035e565b34801561064f57600080fd5b5061030e61065e366004613535565b611506565b34801561066f57600080fd5b50610331611531565b34801561068457600080fd5b5061044b61069336600461368b565b611540565b3480156106a457600080fd5b506102b76106b3366004613856565b6116ba565b3480156106c457600080fd5b50600b5461030e565b3480156106d957600080fd5b506102b76106e83660046138ac565b611750565b6102b76106fb3660046135dd565b61175f565b34801561070c57600080fd5b506102b761071b366004613925565b611863565b34801561072c57600080fd5b506102b761073b366004613856565b61189b565b6102b761074e366004613756565b61198a565b34801561075f57600080fd5b5061033161076e366004613535565b611b94565b34801561077f57600080fd5b506102b761078e3660046135dd565b611c07565b34801561079f57600080fd5b5061030e60001981565b3480156107b557600080fd5b506102b76107c43660046135dd565b611dac565b3480156107d557600080fd5b506102b76107e43660046135dd565b611e91565b3480156107f557600080fd5b506102b761080436600461368b565b611f05565b34801561081557600080fd5b506102d96108243660046139e8565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561085e57600080fd5b506102b761086d3660046135dd565b611fe1565b61030e610880366004613a16565b612057565b34801561089157600080fd5b5061030e600a81565b3480156108a657600080fd5b506102b76108b53660046137a1565b61215c565b6108c26121d5565b816108cc81612222565b600083815260086020526040902060028101546108e890612277565b156109325760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093b846122eb565b610945818461238e565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b257506001600160e01b03198216635b5e139f60e01b145b806109cd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109de8261244d565b6000828152600860205260409020600201546109cd90612277565b606060008054610a0890613adc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3490613adc565b8015610a815780601f10610a5657610100808354040283529160200191610a81565b820191906000526020600020905b815481529060010190602001808311610a6457829003601f168201915b5050505050905090565b6000610a968261244d565b506000908152600460205260409020546001600160a01b031690565b6000610abd8261116c565b9050806001600160a01b0316836001600160a01b031603610b2a5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610929565b336001600160a01b0382161480610b465750610b468133610824565b610bb85760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610929565b610bc283836124ac565b505050565b610bcf6121d5565b81610bd981612222565b6000838152600860205260409020610bf1908361251a565b6040516001600160a01b038316815283907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a2505050565b610c3c6121d5565b81610c4681612222565b6000838152600860205260409020610c5d81612618565b610c678184612662565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c9991815260200190565b60405180910390a250505050565b610cb1338261274f565b610ccd5760405162461bcd60e51b815260040161092990613b16565b610bc28383836127cd565b610ce06121d5565b80610cea81612222565b6000828152600860205260409020610d0181612618565b610d0a8161293e565b15610d4e5760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b610d57816129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d8f612a1a565b610d97612a74565b565b6060816001600160401b03811115610db357610db36138df565b604051908082528060200260200182016040528015610de657816020015b6060815260200190600190039081610dd15790505b5090506000610df4600b5490565b905060005b83811015610f1357816001600160401b03811115610e1957610e196138df565b604051908082528060200260200182016040528015610e42578160200160208202803683370190505b50838281518110610e5557610e55613b63565b60200260200101819052506000600a6000878785818110610e7857610e78613b63565b9050602002016020810190610e8d91906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b83811015610f09576000818152602083905260409020548551869085908110610edd57610edd613b63565b60200260200101518281518110610ef657610ef6613b63565b6020908102919091010152600101610eb2565b5050600101610df9565b505092915050565b610bc283838360405180602001604052806000815250611863565b6000806000806000610f478661244d565b60008681526008602052604081208054600b80549293929091908110610f6f57610f6f613b63565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a509198509296506001600160a01b031694509092505050565b6000610fc6610fc18484612ac9565b612b30565b9392505050565b610fd56121d5565b60008060005b8481101561106c57858582818110610ff557610ff5613b63565b90506020020135925061100783612222565b6000838152600860205260409020915061102082612618565b61102a8285612662565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b8560405161105c91815260200190565b60405180910390a2600101610fdb565b505050505050565b61107c6121d5565b60008060005b838110156111035784848281811061109c5761109c613b63565b9050602002013592506110ae83612222565b600083815260086020526040902091506110c782612b61565b6110d082612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2600101611082565b5050505050565b6111126121d5565b8061111c81612222565b600082815260086020526040902061113381612b61565b61113c81612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cd5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b60006001600160a01b0382166112365760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610929565b506001600160a01b031660009081526003602052604090205490565b600061125c6121d5565b6000821180156112745750346112728387613b8f565b145b6112905760405162461bcd60e51b815260040161092990613ba6565b600061129c8686612ac9565b90506112a781612bff565b600754600101915060005b83811015611320576112c48286612c4b565b6112ce8184613bd2565b604080516001600160a01b0388168152602081018a90529081018890527f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a26001016112b2565b50505b949350505050565b611333612a1a565b610d976000612ce5565b606060008211801561135a5750600b546113578385613bd2565b11155b6113765760405162461bcd60e51b815260040161092990613ba6565b816001600160401b0381111561138e5761138e6138df565b6040519080825280602002602001820160405280156113e357816020015b6113d060405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816113ac5790505b50905060005b8281101561146b57600b8185018154811061140657611406613b63565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061144f5761144f613b63565b60200260200101819052506114648160010190565b90506113e9565b5092915050565b600061147c6121d5565b3460006114898286612ac9565b905061149481612bff565b61149e8185612c4b565b600754604080516001600160a01b03871681526020810185905290810187905281907f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a295945050505050565b6114fe612a1a565b610d97612d37565b60006115118261244d565b600082815260086020526040902061152881612618565b610fc68161293e565b606060018054610a0890613adc565b6060816001600160401b0381111561155a5761155a6138df565b60405190808252806020026020018201604052801561158d57816020015b60608152602001906001900390816115785790505b509050600061159b600b5490565b905060005b83811015610f1357816001600160401b038111156115c0576115c06138df565b6040519080825280602002602001820160405280156115e9578160200160208202803683370190505b508382815181106115fc576115fc613b63565b602002602001018190525060006009600087878581811061161f5761161f613b63565b905060200201602081019061163491906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b838110156116b057600081815260208390526040902054855186908590811061168457611684613b63565b6020026020010151828151811061169d5761169d613b63565b6020908102919091010152600101611659565b50506001016115a0565b6116c26121d5565b6000805b83811015611103578484828181106116e0576116e0613b63565b9050602002013591506116f282612222565b600082815260086020526040902061170a908461251a565b6040516001600160a01b038416815282907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a26001016116c6565b61175b338383612d7a565b5050565b6117676121d5565b8161177181612222565b600083815260086020526040902061178881612b61565b8054600b805460009190839081106117a2576117a2613b63565b90600052602060002090600302019050848160000154346117c39190613bd2565b146117e05760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a602090815260408083208584529091529020805460001901905560018101546118219084908790612e48565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161185391815260200190565b60405180910390a2505050505050565b61186d338361274f565b6118895760405162461bcd60e51b815260040161092990613b16565b61189584848484612e94565b50505050565b6118a36121d5565b60008060005b8481101561106c578585828181106118c3576118c3613b63565b9050602002013592506118d583612222565b600083815260086020526040902060028101549092506118f490612277565b156119395760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b6044820152606401610929565b611942836122eb565b61194c828561238e565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016118a9565b6119926121d5565b600182116119d35760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610929565b3460008080855b8015611b8a57600019018787828181106119f6576119f6613b63565b905060200201359350611a0884612222565b60008481526008602052604090209250611a2183612618565b82546003840154600b80546001600160a01b039092169183908110611a4857611a48613b63565b906000526020600020906003020193508360010154881015611a9f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b8354611aab9088613bd2565b9650611abd8560010154600019141590565b15611af2576001600160a01b038116600090815260096020908152604080832085845290915290208054600019019055611b1e565b6001600160a01b0381166000908152600a60209081526040808320858452909152902080546000190190555b8215611b3257611b2d866122eb565b611b83565b6000196001860155611b4585888a612e48565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611b7a9493929190613c10565b60405180910390a15b50506119da565b5050505050505050565b6060611b9f8261244d565b6000611bb660408051602081019091526000815290565b90506000815111611bd65760405180602001604052806000815250610fc6565b80611be084612ec7565b604051602001611bf1929190613c56565b6040516020818303038152906040529392505050565b611c0f612a1a565b81600003611c535760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b6044820152606401610929565b6000828152600c6020908152604080832084845290915290205415611cb25760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b6044820152606401610929565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b611db46121d5565b81611dbe81612222565b6000838152600860205260409020611dd581612b61565b8054600b80546000919083908110611def57611def613b63565b9060005260206000209060030201905080600101548511611e225760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a60209081526040808320858452909152902080546000190190558054611e5f90849087612e48565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161185391815260200190565b611e99612a1a565b43600b611ea68484612ac9565b81548110611eb657611eb6613b63565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611da0929190918252602082015260400190565b611f0d6121d5565b60008060005b8381101561110357848482818110611f2d57611f2d613b63565b905060200201359250611f3f83612222565b60008381526008602052604090209150611f5882612618565b611f618261293e565b15611fa55760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b611fae826129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611f13565b611fe9612a1a565b600019600b611ff88484612ac9565b8154811061200857612008613b63565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611da0929190918252602082015260400190565b60006120616121d5565b3482518561206f9190613b8f565b1461208c5760405162461bcd60e51b815260040161092990613ba6565b60006120988585612ac9565b90506120a381612bff565b600754600101915060005b8351811015612153576120da828583815181106120cd576120cd613b63565b6020026020010151612c4b565b6120e48184613bd2565b7f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a3285838151811061211757612117613b63565b602090810291909101810151604080516001600160a01b0390921682529181018a905290810188905260600160405180910390a26001016120ae565b50509392505050565b612164612a1a565b6001600160a01b0381166121c95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610929565b6121d281612ce5565b50565b600654600160a01b900460ff1615610d975760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610929565b61222b8161116c565b6001600160a01b0316336001600160a01b0316146121d25760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606401610929565b600060001982036122c35760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b6044820152606401610929565b60006122d0600a84613bd2565b90504381116122e25750600092915050565b43900392915050565b60006122f68261116c565b9050612306816000846001612f59565b61230f8261116c565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b8360000154815481106123a7576123a7613b63565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d8060008114612402576040519150601f19603f3d011682016040523d82523d6000602084013e612407565b606091505b50509050806118955760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b6044820152606401610929565b6000818152600260205260409020546001600160a01b03166121d25760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124e18261116c565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b61252382612618565b815460038301546001600160a01b0390811690831681036125565760405162461bcd60e51b815260040161092990613be5565b6001840154600019146125ac576001600160a01b038181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556125f1565b6001600160a01b038181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546001600160a01b0319166001600160a01b03909216919091179055565b6002810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b6044820152606401610929565b815460038301546001600160a01b031661267b8461293e565b8310156126bd5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b60006126ed600b84815481106126d5576126d5613b63565b90600052602060002090600302016000015485612ac9565b90506126f881612bff565b60001960018681018290556001600160a01b039390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061275b8361116c565b9050806001600160a01b0316846001600160a01b031614806127a257506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806113235750836001600160a01b03166127bb84610a8b565b6001600160a01b031614949350505050565b826001600160a01b03166127e08261116c565b6001600160a01b0316146128065760405162461bcd60e51b815260040161092990613c85565b6001600160a01b0382166128685760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610929565b6128758383836001612f59565b826001600160a01b03166128888261116c565b6001600160a01b0316146128ae5760405162461bcd60e51b815260040161092990613c85565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600181015460009060001981036129905760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b6044820152606401610929565b6000600b8460000154815481106129a9576129a9613b63565b906000526020600020906003020160010154826129c69190613bd2565b90504381116129d9575060009392505050565b4390039392505050565b43600282015560038101546001600160a01b0316600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d975760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610929565b612a7c613029565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b265760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b6044820152606401610929565b6000198101611323565b600043600b8381548110612b4657612b46613b63565b90600052602060002090600302016002015411159050919050565b6001810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b6044820152606401610929565b80546003820154436001938401556001600160a01b03166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b612c0881612b30565b6121d25760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b6044820152606401610929565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0389811660608601818152600098895260088552878920965187559251868a0155935160028601559051600390940180546001600160a01b03191694909116939093179092558352600a815281832087845290529020805490910190555461175b903390613079565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d3f6121d5565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612aac3390565b816001600160a01b0316836001600160a01b031603612ddb5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610929565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e548383612ac9565b9050612e5f81612bff565b60038401546001600160a01b03166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e9f8484846127cd565b612eab84848484613093565b6118955760405162461bcd60e51b815260040161092990613cca565b60606000612ed483613191565b60010190506000816001600160401b03811115612ef357612ef36138df565b6040519080825280601f01601f191660200182016040528015612f1d576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f2757509392505050565b80600114612fa95760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f72746564006044820152606401610929565b6001600160a01b0383161580612fd15750600082815260086020526040902060020154600019145b61301d5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e00006044820152606401610929565b61189584848484613269565b600654600160a01b900460ff16610d975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610929565b61175b8282604051806020016040528060008152506132f1565b60006001600160a01b0384163b1561318957604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130d7903390899088908890600401613d1c565b6020604051808303816000875af1925050508015613112575060408051601f3d908101601f1916820190925261310f91810190613d59565b60015b61316f573d808015613140576040519150601f19603f3d011682016040523d82523d6000602084013e613145565b606091505b5080516000036131675760405162461bcd60e51b815260040161092990613cca565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611323565b506001611323565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131d05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131fc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061321a57662386f26fc10000830492506010015b6305f5e1008310613232576305f5e100830492506008015b612710831061324657612710830492506004015b60648310613258576064830492506002015b600a83106109cd5760010192915050565b6001811115611895576001600160a01b038416156132af576001600160a01b038416600090815260036020526040812080548392906132a9908490613d76565b90915550505b6001600160a01b03831615611895576001600160a01b038316600090815260036020526040812080548392906132e6908490613bd2565b909155505050505050565b6132fb8383613324565b6133086000848484613093565b610bc25760405162461bcd60e51b815260040161092990613cca565b6001600160a01b03821661337a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610929565b6000818152600260205260409020546001600160a01b0316156133df5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6133ed600083836001612f59565b6000818152600260205260409020546001600160a01b0316156134525760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121d257600080fd5b600080604083850312156134e557600080fd5b8235915060208301356134f7816134bd565b809150509250929050565b6001600160e01b0319811681146121d257600080fd5b60006020828403121561352a57600080fd5b8135610fc681613502565b60006020828403121561354757600080fd5b5035919050565b60005b83811015613569578181015183820152602001613551565b50506000910152565b6000815180845261358a81602086016020860161354e565b601f01601f19169290920160200192915050565b602081526000610fc66020830184613572565b600080604083850312156135c457600080fd5b82356135cf816134bd565b946020939093013593505050565b600080604083850312156135f057600080fd5b50508035926020909101359150565b60008060006060848603121561361457600080fd5b833561361f816134bd565b9250602084013561362f816134bd565b929592945050506040919091013590565b60008083601f84011261365257600080fd5b5081356001600160401b0381111561366957600080fd5b6020830191508360208260051b850101111561368457600080fd5b9250929050565b6000806020838503121561369e57600080fd5b82356001600160401b038111156136b457600080fd5b6136c085828601613640565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b8381101561374857888603603f19018552825180518088529088019088880190845b818110156137325783518352928a0192918a0191600101613716565b50909750505093860193918601916001016136f4565b509398975050505050505050565b60008060006040848603121561376b57600080fd5b83356001600160401b0381111561378157600080fd5b61378d86828701613640565b909790965060209590950135949350505050565b6000602082840312156137b357600080fd5b8135610fc6816134bd565b600080600080608085870312156137d457600080fd5b843593506020850135925060408501356137ed816134bd565b9396929550929360600135925050565b602080825282518282018190526000919060409081850190868401855b82811015613849578151805185528681015187860152850151858501526060909301929085019060010161381a565b5091979650505050505050565b60008060006040848603121561386b57600080fd5b83356001600160401b0381111561388157600080fd5b61388d86828701613640565b90945092505060208401356138a1816134bd565b809150509250925092565b600080604083850312156138bf57600080fd5b82356138ca816134bd565b9150602083013580151581146134f757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561391d5761391d6138df565b604052919050565b6000806000806080858703121561393b57600080fd5b8435613946816134bd565b9350602085810135613957816134bd565b93506040860135925060608601356001600160401b038082111561397a57600080fd5b818801915088601f83011261398e57600080fd5b8135818111156139a0576139a06138df565b6139b2601f8201601f191685016138f5565b915080825289848285010111156139c857600080fd5b808484018584013760008482840101525080935050505092959194509250565b600080604083850312156139fb57600080fd5b8235613a06816134bd565b915060208301356134f7816134bd565b600080600060608486031215613a2b57600080fd5b83359250602080850135925060408501356001600160401b0380821115613a5157600080fd5b818701915087601f830112613a6557600080fd5b813581811115613a7757613a776138df565b8060051b9150613a888483016138f5565b818152918301840191848101908a841115613aa257600080fd5b938501935b83851015613acc5784359250613abc836134bd565b8282529385019390850190613aa7565b8096505050505050509250925092565b600181811c90821680613af057607f821691505b602082108103613b1057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176109cd576109cd613b79565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b808201808211156109cd576109cd613b79565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3057600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6881846020880161354e565b835190830190613c7c81836020880161354e565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d4f90830184613572565b9695505050505050565b600060208284031215613d6b57600080fd5b8151610fc681613502565b818103818111156109cd576109cd613b7956fea2646970667358221220be917767ef1b31d340fe6087913ba2e72285104d0b6c49192dabe393bb91652864736f6c63430008120033` - _liquidStakingContractABI = `[ + // _stakingContractByteCode is the byte code of the contract staking contract for testing, which changes the freeze blocks to 10 + _stakingContractByteCode = `60806040523480156200001157600080fd5b5060405180604001604052806009815260200168109d58dad95d13919560ba1b815250604051806040016040528060038152602001621092d560ea1b81525081600090816200006191906200019b565b5060016200007082826200019b565b5050506200008d62000087620000a060201b60201c565b620000a4565b6006805460ff60a01b1916905562000267565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200012157607f821691505b6020821081036200014257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200019657600081815260208120601f850160051c81016020861015620001715750805b601f850160051c820191505b8181101562000192578281556001016200017d565b5050505b505050565b81516001600160401b03811115620001b757620001b7620000f6565b620001cf81620001c884546200010c565b8462000148565b602080601f831160018114620002075760008415620001ee5750858301515b600019600386901b1c1916600185901b17855562000192565b600085815260208120601f198616915b82811015620002385788860151825594840194600190910190840162000217565b5085821015620002575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613dbf80620002776000396000f3fe6080604052600436106102925760003560e01c80637acb77571161015a578063bbe33ea5116100c1578063e449f3411161007a578063e449f341146107e9578063e985e9c514610809578063eb0ffb2e14610852578063eec7ee7314610872578063f0b56b5d14610885578063f2fde38b1461089a57600080fd5b8063bbe33ea514610740578063c87b56dd14610753578063c8e7792314610773578063d0949f9914610793578063d6605fd8146107a9578063e0028ecf146107c957600080fd5b806398ca3b761161011357806398ca3b76146106985780639f7d5b00146106b8578063a22cb465146106cd578063b2383e55146106ed578063b88d4fde14610700578063b8f4bd7b1461072057600080fd5b80637acb7757146105fd5780638456cb59146106105780638da5cb5b1461062557806393b6ef591461064357806395d89b4114610663578063960014bd1461067857600080fd5b806342842e0e116101fe5780636198e339116101b75780636198e339146105485780636352211e1461056857806370a0823114610588578063711563d4146105a8578063715018a6146105bb57806378bfca10146105d057600080fd5b806342842e0e14610458578063431cd92a1461047857806343e06c59146104c95780635c975abb146104e95780635ceb8b5b146105085780635d36598f1461052857600080fd5b80630f5b2ca5116102505780630f5b2ca5146103965780631338736f146103b657806323b872dd146103d65780632e17de78146103f65780633f4ba83a146104165780633fd140df1461042b57600080fd5b8062f714ce1461029757806301ffc9a7146102b957806303459b16146102ee57806306fdde031461031c578063081812fc1461033e578063095ea7b314610376575b600080fd5b3480156102a357600080fd5b506102b76102b23660046134d2565b6108ba565b005b3480156102c557600080fd5b506102d96102d4366004613518565b610981565b60405190151581526020015b60405180910390f35b3480156102fa57600080fd5b5061030e610309366004613535565b6109d3565b6040519081526020016102e5565b34801561032857600080fd5b506103316109f9565b6040516102e5919061359e565b34801561034a57600080fd5b5061035e610359366004613535565b610a8b565b6040516001600160a01b0390911681526020016102e5565b34801561038257600080fd5b506102b76103913660046135b1565b610ab2565b3480156103a257600080fd5b506102b76103b13660046134d2565b610bc7565b3480156103c257600080fd5b506102b76103d13660046135dd565b610c34565b3480156103e257600080fd5b506102b76103f13660046135ff565b610ca7565b34801561040257600080fd5b506102b7610411366004613535565b610cd8565b34801561042257600080fd5b506102b7610d87565b34801561043757600080fd5b5061044b61044636600461368b565b610d99565b6040516102e591906136cc565b34801561046457600080fd5b506102b76104733660046135ff565b610f1b565b34801561048457600080fd5b50610498610493366004613535565b610f36565b6040805195865260208601949094529284019190915260608301526001600160a01b0316608082015260a0016102e5565b3480156104d557600080fd5b506102d96104e43660046135dd565b610fb2565b3480156104f557600080fd5b50600654600160a01b900460ff166102d9565b34801561051457600080fd5b506102b7610523366004613756565b610fcd565b34801561053457600080fd5b506102b761054336600461368b565b611074565b34801561055457600080fd5b506102b7610563366004613535565b61110a565b34801561057457600080fd5b5061035e610583366004613535565b61116c565b34801561059457600080fd5b5061030e6105a33660046137a1565b6111cc565b61030e6105b63660046137be565b611252565b3480156105c757600080fd5b506102b761132b565b3480156105dc57600080fd5b506105f06105eb3660046135dd565b61133d565b6040516102e591906137fd565b61030e61060b3660046134d2565b611472565b34801561061c57600080fd5b506102b76114f6565b34801561063157600080fd5b506006546001600160a01b031661035e565b34801561064f57600080fd5b5061030e61065e366004613535565b611506565b34801561066f57600080fd5b50610331611531565b34801561068457600080fd5b5061044b61069336600461368b565b611540565b3480156106a457600080fd5b506102b76106b3366004613856565b6116ba565b3480156106c457600080fd5b50600b5461030e565b3480156106d957600080fd5b506102b76106e83660046138ac565b611750565b6102b76106fb3660046135dd565b61175f565b34801561070c57600080fd5b506102b761071b366004613925565b611863565b34801561072c57600080fd5b506102b761073b366004613856565b61189b565b6102b761074e366004613756565b61198a565b34801561075f57600080fd5b5061033161076e366004613535565b611b94565b34801561077f57600080fd5b506102b761078e3660046135dd565b611c07565b34801561079f57600080fd5b5061030e60001981565b3480156107b557600080fd5b506102b76107c43660046135dd565b611dac565b3480156107d557600080fd5b506102b76107e43660046135dd565b611e91565b3480156107f557600080fd5b506102b761080436600461368b565b611f05565b34801561081557600080fd5b506102d96108243660046139e8565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561085e57600080fd5b506102b761086d3660046135dd565b611fe1565b61030e610880366004613a16565b612057565b34801561089157600080fd5b5061030e600a81565b3480156108a657600080fd5b506102b76108b53660046137a1565b61215c565b6108c26121d5565b816108cc81612222565b600083815260086020526040902060028101546108e890612277565b156109325760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b60448201526064015b60405180910390fd5b61093b846122eb565b610945818461238e565b6040516001600160a01b0384169085907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a350505050565b60006001600160e01b031982166380ac58cd60e01b14806109b257506001600160e01b03198216635b5e139f60e01b145b806109cd57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60006109de8261244d565b6000828152600860205260409020600201546109cd90612277565b606060008054610a0890613adc565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3490613adc565b8015610a815780601f10610a5657610100808354040283529160200191610a81565b820191906000526020600020905b815481529060010190602001808311610a6457829003601f168201915b5050505050905090565b6000610a968261244d565b506000908152600460205260409020546001600160a01b031690565b6000610abd8261116c565b9050806001600160a01b0316836001600160a01b031603610b2a5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610929565b336001600160a01b0382161480610b465750610b468133610824565b610bb85760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610929565b610bc283836124ac565b505050565b610bcf6121d5565b81610bd981612222565b6000838152600860205260409020610bf1908361251a565b6040516001600160a01b038316815283907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a2505050565b610c3c6121d5565b81610c4681612222565b6000838152600860205260409020610c5d81612618565b610c678184612662565b837f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b84604051610c9991815260200190565b60405180910390a250505050565b610cb1338261274f565b610ccd5760405162461bcd60e51b815260040161092990613b16565b610bc28383836127cd565b610ce06121d5565b80610cea81612222565b6000828152600860205260409020610d0181612618565b610d0a8161293e565b15610d4e5760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b610d57816129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2505050565b610d8f612a1a565b610d97612a74565b565b6060816001600160401b03811115610db357610db36138df565b604051908082528060200260200182016040528015610de657816020015b6060815260200190600190039081610dd15790505b5090506000610df4600b5490565b905060005b83811015610f1357816001600160401b03811115610e1957610e196138df565b604051908082528060200260200182016040528015610e42578160200160208202803683370190505b50838281518110610e5557610e55613b63565b60200260200101819052506000600a6000878785818110610e7857610e78613b63565b9050602002016020810190610e8d91906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b83811015610f09576000818152602083905260409020548551869085908110610edd57610edd613b63565b60200260200101518281518110610ef657610ef6613b63565b6020908102919091010152600101610eb2565b5050600101610df9565b505092915050565b610bc283838360405180602001604052806000815250611863565b6000806000806000610f478661244d565b60008681526008602052604081208054600b80549293929091908110610f6f57610f6f613b63565b6000918252602090912060039182020180546001918201549185015460028601549590930154909b919a509198509296506001600160a01b031694509092505050565b6000610fc6610fc18484612ac9565b612b30565b9392505050565b610fd56121d5565b60008060005b8481101561106c57858582818110610ff557610ff5613b63565b90506020020135925061100783612222565b6000838152600860205260409020915061102082612618565b61102a8285612662565b827f907fece23ce39fbcbceb71e515043fe29408353fbb393b25b35eb8a70a4bad0b8560405161105c91815260200190565b60405180910390a2600101610fdb565b505050505050565b61107c6121d5565b60008060005b838110156111035784848281811061109c5761109c613b63565b9050602002013592506110ae83612222565b600083815260086020526040902091506110c782612b61565b6110d082612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2600101611082565b5050505050565b6111126121d5565b8061111c81612222565b600082815260086020526040902061113381612b61565b61113c81612bab565b60405183907ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f184290600090a2505050565b6000818152600260205260408120546001600160a01b0316806109cd5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b60006001600160a01b0382166112365760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610929565b506001600160a01b031660009081526003602052604090205490565b600061125c6121d5565b6000821180156112745750346112728387613b8f565b145b6112905760405162461bcd60e51b815260040161092990613ba6565b600061129c8686612ac9565b90506112a781612bff565b600754600101915060005b83811015611320576112c48286612c4b565b6112ce8184613bd2565b604080516001600160a01b0388168152602081018a90529081018890527f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a26001016112b2565b50505b949350505050565b611333612a1a565b610d976000612ce5565b606060008211801561135a5750600b546113578385613bd2565b11155b6113765760405162461bcd60e51b815260040161092990613ba6565b816001600160401b0381111561138e5761138e6138df565b6040519080825280602002602001820160405280156113e357816020015b6113d060405180606001604052806000815260200160008152602001600081525090565b8152602001906001900390816113ac5790505b50905060005b8281101561146b57600b8185018154811061140657611406613b63565b9060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505082828151811061144f5761144f613b63565b60200260200101819052506114648160010190565b90506113e9565b5092915050565b600061147c6121d5565b3460006114898286612ac9565b905061149481612bff565b61149e8185612c4b565b600754604080516001600160a01b03871681526020810185905290810187905281907f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a329060600160405180910390a295945050505050565b6114fe612a1a565b610d97612d37565b60006115118261244d565b600082815260086020526040902061152881612618565b610fc68161293e565b606060018054610a0890613adc565b6060816001600160401b0381111561155a5761155a6138df565b60405190808252806020026020018201604052801561158d57816020015b60608152602001906001900390816115785790505b509050600061159b600b5490565b905060005b83811015610f1357816001600160401b038111156115c0576115c06138df565b6040519080825280602002602001820160405280156115e9578160200160208202803683370190505b508382815181106115fc576115fc613b63565b602002602001018190525060006009600087878581811061161f5761161f613b63565b905060200201602081019061163491906137a1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b838110156116b057600081815260208390526040902054855186908590811061168457611684613b63565b6020026020010151828151811061169d5761169d613b63565b6020908102919091010152600101611659565b50506001016115a0565b6116c26121d5565b6000805b83811015611103578484828181106116e0576116e0613b63565b9050602002013591506116f282612222565b600082815260086020526040902061170a908461251a565b6040516001600160a01b038416815282907f6f08c7e76d830d5f3d0a18fd27f4d8c0049b24a8689ddb39625e0864d894a9c19060200160405180910390a26001016116c6565b61175b338383612d7a565b5050565b6117676121d5565b8161177181612222565b600083815260086020526040902061178881612b61565b8054600b805460009190839081106117a2576117a2613b63565b90600052602060002090600302019050848160000154346117c39190613bd2565b146117e05760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a602090815260408083208584529091529020805460001901905560018101546118219084908790612e48565b857f1d9c4d2b3e13eb9ac08a42625750ac17ec6ca94b4755c49285e9467b4e48c89d8660405161185391815260200190565b60405180910390a2505050505050565b61186d338361274f565b6118895760405162461bcd60e51b815260040161092990613b16565b61189584848484612e94565b50505050565b6118a36121d5565b60008060005b8481101561106c578585828181106118c3576118c3613b63565b9050602002013592506118d583612222565b600083815260086020526040902060028101549092506118f490612277565b156119395760405162461bcd60e51b81526020600482015260156024820152746e6f7420726561647920746f20776974686472617760581b6044820152606401610929565b611942836122eb565b61194c828561238e565b6040516001600160a01b0385169084907fd964a27d45f595739c13d8b1160b57491050cacf3a2e5602207277d6228f64ee90600090a36001016118a9565b6119926121d5565b600182116119d35760405162461bcd60e51b815260206004820152600e60248201526d0d2dcecc2d8d2c840d8cadccee8d60931b6044820152606401610929565b3460008080855b8015611b8a57600019018787828181106119f6576119f6613b63565b905060200201359350611a0884612222565b60008481526008602052604090209250611a2183612618565b82546003840154600b80546001600160a01b039092169183908110611a4857611a48613b63565b906000526020600020906003020193508360010154881015611a9f5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b8354611aab9088613bd2565b9650611abd8560010154600019141590565b15611af2576001600160a01b038116600090815260096020908152604080832085845290915290208054600019019055611b1e565b6001600160a01b0381166000908152600a60209081526040808320858452909152902080546000190190555b8215611b3257611b2d866122eb565b611b83565b6000196001860155611b4585888a612e48565b7fb3f4c8ca702dbbd32d9a25ce17b1942a5060284d9d69fc4fcac8fb0397891b128a8a898b604051611b7a9493929190613c10565b60405180910390a15b50506119da565b5050505050505050565b6060611b9f8261244d565b6000611bb660408051602081019091526000815290565b90506000815111611bd65760405180602001604052806000815250610fc6565b80611be084612ec7565b604051602001611bf1929190613c56565b6040516020818303038152906040529392505050565b611c0f612a1a565b81600003611c535760405162461bcd60e51b8152602060048201526011602482015270185b5bdd5b9d081a5cc81a5b9d985b1a59607a1b6044820152606401610929565b6000828152600c6020908152604080832084845290915290205415611cb25760405162461bcd60e51b81526020600482015260156024820152746475706c6963617465206275636b6574207479706560581b6044820152606401610929565b60408051606081018252838152602080820184815243838501908152600b8054600181018255600082815295517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db960039092029182015592517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dba84015590517f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01dbb9092019190915554858352600c82528383208584528252918390209190915581518481529081018390527f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b791015b60405180910390a15050565b611db46121d5565b81611dbe81612222565b6000838152600860205260409020611dd581612b61565b8054600b80546000919083908110611def57611def613b63565b9060005260206000209060030201905080600101548511611e225760405162461bcd60e51b815260040161092990613be5565b60038301546001600160a01b03166000908152600a60209081526040808320858452909152902080546000190190558054611e5f90849087612e48565b857fc599168ac63ff28ec278088a2c424383a36ca26c931eb41af05e014f19252ea48660405161185391815260200190565b611e99612a1a565b43600b611ea68484612ac9565b81548110611eb657611eb6613b63565b9060005260206000209060030201600201819055507f6b39e3267efcd6611c8d7d2534c4715dcb4824322b90d85540a3a82967b6e7b78282604051611da0929190918252602082015260400190565b611f0d6121d5565b60008060005b8381101561110357848482818110611f2d57611f2d613b63565b905060200201359250611f3f83612222565b60008381526008602052604090209150611f5882612618565b611f618261293e565b15611fa55760405162461bcd60e51b81526020600482015260146024820152736e6f7420726561647920746f20756e7374616b6560601b6044820152606401610929565b611fae826129e3565b60405183907f11725367022c3ff288940f4b5473aa61c2da6a24af7363a1128ee2401e8983b290600090a2600101611f13565b611fe9612a1a565b600019600b611ff88484612ac9565b8154811061200857612008613b63565b9060005260206000209060030201600201819055507f099df2bf9247b43481cf1b791a4dd5fa1220c40c62940da539082fbcb30241d68282604051611da0929190918252602082015260400190565b60006120616121d5565b3482518561206f9190613b8f565b1461208c5760405162461bcd60e51b815260040161092990613ba6565b60006120988585612ac9565b90506120a381612bff565b600754600101915060005b8351811015612153576120da828583815181106120cd576120cd613b63565b6020026020010151612c4b565b6120e48184613bd2565b7f17700ceb1658b18206f427c1578048e87504106b14ec69e9b4586d9a95174a3285838151811061211757612117613b63565b602090810291909101810151604080516001600160a01b0390921682529181018a905290810188905260600160405180910390a26001016120ae565b50509392505050565b612164612a1a565b6001600160a01b0381166121c95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610929565b6121d281612ce5565b50565b600654600160a01b900460ff1615610d975760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610929565b61222b8161116c565b6001600160a01b0316336001600160a01b0316146121d25760405162461bcd60e51b81526020600482015260096024820152683737ba1037bbb732b960b91b6044820152606401610929565b600060001982036122c35760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9cdd185ad95908189d58dad95d60521b6044820152606401610929565b60006122d0600a84613bd2565b90504381116122e25750600092915050565b43900392915050565b60006122f68261116c565b9050612306816000846001612f59565b61230f8261116c565b600083815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526003845282852080546000190190558785526002909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000600b8360000154815481106123a7576123a7613b63565b600091825260208220600390910201546040519092506001600160a01b0384169083908381818185875af1925050503d8060008114612402576040519150601f19603f3d011682016040523d82523d6000602084013e612407565b606091505b50509050806118955760405162461bcd60e51b81526020600482015260126024820152713330b4b632b2103a37903a3930b739b332b960711b6044820152606401610929565b6000818152600260205260409020546001600160a01b03166121d25760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610929565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906124e18261116c565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b61252382612618565b815460038301546001600160a01b0390811690831681036125565760405162461bcd60e51b815260040161092990613be5565b6001840154600019146125ac576001600160a01b038181166000908152600960208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190556125f1565b6001600160a01b038181166000908152600a60208181526040808420878552825280842080546000190190559387168352908152828220858352905220805460010190555b505060039190910180546001600160a01b0319166001600160a01b03909216919091179055565b6002810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba10309039ba30b5b2b2103a37b5b2b760711b6044820152606401610929565b815460038301546001600160a01b031661267b8461293e565b8310156126bd5760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b210323ab930ba34b7b760811b6044820152606401610929565b60006126ed600b84815481106126d5576126d5613b63565b90600052602060002090600302016000015485612ac9565b90506126f881612bff565b60001960018681018290556001600160a01b039390931660008181526009602090815260408083209783529681528682208054909401909355968390558652600a8152838620918652529220805490920190915550565b60008061275b8361116c565b9050806001600160a01b0316846001600160a01b031614806127a257506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806113235750836001600160a01b03166127bb84610a8b565b6001600160a01b031614949350505050565b826001600160a01b03166127e08261116c565b6001600160a01b0316146128065760405162461bcd60e51b815260040161092990613c85565b6001600160a01b0382166128685760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610929565b6128758383836001612f59565b826001600160a01b03166128888261116c565b6001600160a01b0316146128ae5760405162461bcd60e51b815260040161092990613c85565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600181015460009060001981036129905760405162461bcd60e51b81526020600482015260166024820152751b9bdd08185b881d5b9b1bd8dad95908189d58dad95d60521b6044820152606401610929565b6000600b8460000154815481106129a9576129a9613b63565b906000526020600020906003020160010154826129c69190613bd2565b90504381116129d9575060009392505050565b4390039392505050565b43600282015560038101546001600160a01b0316600090815260096020908152604080832093548352929052208054600019019055565b6006546001600160a01b03163314610d975760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610929565b612a7c613029565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000828152600c6020908152604080832084845290915281205480612b265760405162461bcd60e51b8152602060048201526013602482015272696e76616c6964206275636b6574207479706560681b6044820152606401610929565b6000198101611323565b600043600b8381548110612b4657612b46613b63565b90600052602060002090600302016002015411159050919050565b6001810154600019146121d25760405162461bcd60e51b81526020600482015260126024820152713737ba1030903637b1b5b2b2103a37b5b2b760711b6044820152606401610929565b80546003820154436001938401556001600160a01b03166000818152600a60209081526040808320858452825280832080546000190190559282526009815282822093825292909252902080549091019055565b612c0881612b30565b6121d25760405162461bcd60e51b8152602060048201526014602482015273696e616374697665206275636b6574207479706560601b6044820152606401610929565b6007805460019081018083556040805160808101825286815260001960208083018281528385019283526001600160a01b0389811660608601818152600098895260088552878920965187559251868a0155935160028601559051600390940180546001600160a01b03191694909116939093179092558352600a815281832087845290529020805490910190555461175b903390613079565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b612d3f6121d5565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612aac3390565b816001600160a01b0316836001600160a01b031603612ddb5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610929565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000612e548383612ac9565b9050612e5f81612bff565b60038401546001600160a01b03166000908152600a602090815260408083208484529091529020805460010190559092555050565b612e9f8484846127cd565b612eab84848484613093565b6118955760405162461bcd60e51b815260040161092990613cca565b60606000612ed483613191565b60010190506000816001600160401b03811115612ef357612ef36138df565b6040519080825280601f01601f191660200182016040528015612f1d576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084612f2757509392505050565b80600114612fa95760405162461bcd60e51b815260206004820152601f60248201527f6261746368207472616e73666572206973206e6f7420737570706f72746564006044820152606401610929565b6001600160a01b0383161580612fd15750600082815260086020526040902060020154600019145b61301d5760405162461bcd60e51b815260206004820152601e60248201527f63616e6e6f74207472616e7366657220756e7374616b656420746f6b656e00006044820152606401610929565b61189584848484613269565b600654600160a01b900460ff16610d975760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610929565b61175b8282604051806020016040528060008152506132f1565b60006001600160a01b0384163b1561318957604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906130d7903390899088908890600401613d1c565b6020604051808303816000875af1925050508015613112575060408051601f3d908101601f1916820190925261310f91810190613d59565b60015b61316f573d808015613140576040519150601f19603f3d011682016040523d82523d6000602084013e613145565b606091505b5080516000036131675760405162461bcd60e51b815260040161092990613cca565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611323565b506001611323565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106131d05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106131fc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061321a57662386f26fc10000830492506010015b6305f5e1008310613232576305f5e100830492506008015b612710831061324657612710830492506004015b60648310613258576064830492506002015b600a83106109cd5760010192915050565b6001811115611895576001600160a01b038416156132af576001600160a01b038416600090815260036020526040812080548392906132a9908490613d76565b90915550505b6001600160a01b03831615611895576001600160a01b038316600090815260036020526040812080548392906132e6908490613bd2565b909155505050505050565b6132fb8383613324565b6133086000848484613093565b610bc25760405162461bcd60e51b815260040161092990613cca565b6001600160a01b03821661337a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610929565b6000818152600260205260409020546001600160a01b0316156133df5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6133ed600083836001612f59565b6000818152600260205260409020546001600160a01b0316156134525760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610929565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160a01b03811681146121d257600080fd5b600080604083850312156134e557600080fd5b8235915060208301356134f7816134bd565b809150509250929050565b6001600160e01b0319811681146121d257600080fd5b60006020828403121561352a57600080fd5b8135610fc681613502565b60006020828403121561354757600080fd5b5035919050565b60005b83811015613569578181015183820152602001613551565b50506000910152565b6000815180845261358a81602086016020860161354e565b601f01601f19169290920160200192915050565b602081526000610fc66020830184613572565b600080604083850312156135c457600080fd5b82356135cf816134bd565b946020939093013593505050565b600080604083850312156135f057600080fd5b50508035926020909101359150565b60008060006060848603121561361457600080fd5b833561361f816134bd565b9250602084013561362f816134bd565b929592945050506040919091013590565b60008083601f84011261365257600080fd5b5081356001600160401b0381111561366957600080fd5b6020830191508360208260051b850101111561368457600080fd5b9250929050565b6000806020838503121561369e57600080fd5b82356001600160401b038111156136b457600080fd5b6136c085828601613640565b90969095509350505050565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b8381101561374857888603603f19018552825180518088529088019088880190845b818110156137325783518352928a0192918a0191600101613716565b50909750505093860193918601916001016136f4565b509398975050505050505050565b60008060006040848603121561376b57600080fd5b83356001600160401b0381111561378157600080fd5b61378d86828701613640565b909790965060209590950135949350505050565b6000602082840312156137b357600080fd5b8135610fc6816134bd565b600080600080608085870312156137d457600080fd5b843593506020850135925060408501356137ed816134bd565b9396929550929360600135925050565b602080825282518282018190526000919060409081850190868401855b82811015613849578151805185528681015187860152850151858501526060909301929085019060010161381a565b5091979650505050505050565b60008060006040848603121561386b57600080fd5b83356001600160401b0381111561388157600080fd5b61388d86828701613640565b90945092505060208401356138a1816134bd565b809150509250925092565b600080604083850312156138bf57600080fd5b82356138ca816134bd565b9150602083013580151581146134f757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561391d5761391d6138df565b604052919050565b6000806000806080858703121561393b57600080fd5b8435613946816134bd565b9350602085810135613957816134bd565b93506040860135925060608601356001600160401b038082111561397a57600080fd5b818801915088601f83011261398e57600080fd5b8135818111156139a0576139a06138df565b6139b2601f8201601f191685016138f5565b915080825289848285010111156139c857600080fd5b808484018584013760008482840101525080935050505092959194509250565b600080604083850312156139fb57600080fd5b8235613a06816134bd565b915060208301356134f7816134bd565b600080600060608486031215613a2b57600080fd5b83359250602080850135925060408501356001600160401b0380821115613a5157600080fd5b818701915087601f830112613a6557600080fd5b813581811115613a7757613a776138df565b8060051b9150613a888483016138f5565b818152918301840191848101908a841115613aa257600080fd5b938501935b83851015613acc5784359250613abc836134bd565b8282529385019390850190613aa7565b8096505050505050509250925092565b600181811c90821680613af057607f821691505b602082108103613b1057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176109cd576109cd613b79565b602080825260129082015271696e76616c696420706172616d657465727360701b604082015260600190565b808201808211156109cd576109cd613b79565b60208082526011908201527034b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6060808252810184905260006001600160fb1b03851115613c3057600080fd5b8460051b8087608085013760208301949094525060408101919091520160800192915050565b60008351613c6881846020880161354e565b835190830190613c7c81836020880161354e565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613d4f90830184613572565b9695505050505050565b600060208284031215613d6b57600080fd5b8151610fc681613502565b818103818111156109cd576109cd613b7956fea2646970667358221220be917767ef1b31d340fe6087913ba2e72285104d0b6c49192dabe393bb91652864736f6c63430008120033` + _stakingContractABI = `[ { "inputs": [], "stateMutability": "nonpayable", @@ -1286,7 +1286,7 @@ var ( } ) -func TestLiquidStaking(t *testing.T) { +func TestContractStaking(t *testing.T) { r := require.New(t) // prepare blockchain adminID := _adminID @@ -1296,17 +1296,17 @@ func TestLiquidStaking(t *testing.T) { cfg.Chain.EnableTrielessStateDB = false cfg.Genesis.InitBalanceMap[identityset.Address(adminID).String()] = "1000000000000000000000000000" - bc, sf, dao, ap, indexer := prepareliquidStakingBlockchain(ctx, cfg, r) + bc, sf, dao, ap, indexer := prepareContractStakingBlockchain(ctx, cfg, r) defer func() { r.NoError(bc.Stop(ctx)) }() ctx = genesis.WithGenesisContext(context.Background(), bc.Genesis()) // deploy smart contract - deployAddr := blockindex.LiquidStakingContractAddress + deployAddr := blockindex.StakingContractAddress param := callParam{ contractAddr: deployAddr, - bytecode: _liquidStakingContractByteCode, + bytecode: _stakingContractByteCode, amount: big.NewInt(0), gasLimit: 20000000, gasPrice: big.NewInt(0), @@ -1314,7 +1314,7 @@ func TestLiquidStaking(t *testing.T) { } contractAddresses := deployContracts(bc, sf, dao, ap, ¶m, r) r.Equal(deployAddr, contractAddresses) - lsdABI, err := abi.JSON(strings.NewReader(_liquidStakingContractABI)) + lsdABI, err := abi.JSON(strings.NewReader(_stakingContractABI)) r.NoError(err) // init bucket type @@ -1637,7 +1637,7 @@ func TestLiquidStaking(t *testing.T) { } -func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.ContractStakingIndexer) { +func prepareContractStakingBlockchain(ctx context.Context, cfg config.Config, r *require.Assertions) (blockchain.Blockchain, factory.Factory, blockdao.BlockDAO, actpool.ActPool, blockindex.ContractStakingIndexer) { defer func() { delete(cfg.Plugins, config.GatewayPlugin) }() @@ -1647,9 +1647,9 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r testTriePath, err := testutil.PathOfTempFile("trie") r.NoError(err) defer testutil.CleanupPath(testTriePath) - testLiquidStakeIndexerPath, err := testutil.PathOfTempFile("liquidstakeindexer") + testContractStakeIndexerPath, err := testutil.PathOfTempFile("contractstakeindexer") r.NoError(err) - defer testutil.CleanupPath(testLiquidStakeIndexerPath) + defer testutil.CleanupPath(testContractStakeIndexerPath) cfg.Chain.TrieDBPath = testTriePath cfg.ActPool.MinGasPriceStr = "0" @@ -1704,10 +1704,10 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r indexer, err := blockindex.NewIndexer(db.NewMemKVStore(), cfg.Genesis.Hash()) r.NoError(err) cc := cfg.DB - cc.DbPath = testLiquidStakeIndexerPath - liquidStakeIndexer := blockindex.NewContractStakingIndexer(db.NewBoltDB(cc)) + cc.DbPath = testContractStakeIndexerPath + contractStakeIndexer := blockindex.NewContractStakingIndexer(db.NewBoltDB(cc)) // create BlockDAO - dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, liquidStakeIndexer}) + dao := blockdao.NewBlockDAOInMemForTest([]blockdao.BlockIndexer{sf, indexer, contractStakeIndexer}) r.NotNil(dao) bc := blockchain.NewBlockchain( cfg.Chain, @@ -1727,7 +1727,7 @@ func prepareliquidStakingBlockchain(ctx context.Context, cfg config.Config, r *r r.NoError(execution.Register(registry)) r.NoError(bc.Start(ctx)) - return bc, sf, dao, ap, liquidStakeIndexer + return bc, sf, dao, ap, contractStakeIndexer } func deployContracts( From e7d8c7bf959f934857313cbace77d353087aaa92 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 21:22:41 +0800 Subject: [PATCH 47/51] use only one mutex --- blockindex/liquidstaking_cache.go | 139 +------------------------ blockindex/liquidstaking_cache_test.go | 39 ------- blockindex/liquidstaking_indexer.go | 19 +++- 3 files changed, 17 insertions(+), 180 deletions(-) delete mode 100644 blockindex/liquidstaking_cache_test.go diff --git a/blockindex/liquidstaking_cache.go b/blockindex/liquidstaking_cache.go index c570f56985..5f27a7da2f 100644 --- a/blockindex/liquidstaking_cache.go +++ b/blockindex/liquidstaking_cache.go @@ -7,7 +7,6 @@ package blockindex import ( "math/big" - "sync" "github.com/iotexproject/iotex-address/address" ) @@ -50,21 +49,16 @@ type ( height uint64 totalBucketCount uint64 // total number of buckets including burned buckets } - - contractStakingCacheThreadSafety struct { - cache contractStakingCacheManager - mutex sync.RWMutex - } ) -func newContractStakingCache() *contractStakingCacheThreadSafety { +func newContractStakingCache() *contractStakingCache { cache := &contractStakingCache{ idBucketMap: make(map[uint64]*ContractStakingBucketInfo), idBucketTypeMap: make(map[uint64]*ContractStakingBucketType), propertyBucketTypeMap: make(map[int64]map[uint64]uint64), candidateBucketMap: make(map[string]map[uint64]bool), } - return &contractStakingCacheThreadSafety{cache: cache} + return cache } func (s *contractStakingCache) putHeight(h uint64) { @@ -221,132 +215,3 @@ func (s *contractStakingCache) merge(delta *contractStakingDelta) error { s.putTotalBucketCount(s.getTotalBucketCount() + delta.addedBucketCnt()) return nil } - -func (s *contractStakingCacheThreadSafety) putHeight(h uint64) { - s.mutex.Lock() - defer s.mutex.Unlock() - s.cache.putHeight(h) -} - -func (s *contractStakingCacheThreadSafety) getHeight() uint64 { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getHeight() -} - -func (s *contractStakingCacheThreadSafety) putBucketType(id uint64, bt *ContractStakingBucketType) { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.cache.putBucketType(id, bt) -} - -func (s *contractStakingCacheThreadSafety) putBucketInfo(id uint64, bi *ContractStakingBucketInfo) { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.cache.putBucketInfo(id, bi) -} - -func (s *contractStakingCacheThreadSafety) deleteBucketInfo(id uint64) { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.cache.deleteBucketInfo(id) -} - -func (s *contractStakingCacheThreadSafety) getBucketTypeIndex(amount *big.Int, duration uint64) (uint64, bool) { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getBucketTypeIndex(amount, duration) -} - -func (s *contractStakingCacheThreadSafety) getBucketType(id uint64) (*ContractStakingBucketType, bool) { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getBucketType(id) -} - -func (s *contractStakingCacheThreadSafety) mustGetBucketType(id uint64) *ContractStakingBucketType { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.mustGetBucketType(id) -} - -func (s *contractStakingCacheThreadSafety) getBucketInfo(id uint64) (*ContractStakingBucketInfo, bool) { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getBucketInfo(id) -} - -func (s *contractStakingCacheThreadSafety) mustGetBucketInfo(id uint64) *ContractStakingBucketInfo { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.mustGetBucketInfo(id) -} - -func (s *contractStakingCacheThreadSafety) getCandidateVotes(candidate address.Address) *big.Int { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getCandidateVotes(candidate) -} - -func (s *contractStakingCacheThreadSafety) putTotalBucketCount(count uint64) { - s.mutex.Lock() - defer s.mutex.Unlock() - - s.cache.putTotalBucketCount(count) -} - -func (s *contractStakingCacheThreadSafety) getTotalBucketCount() uint64 { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getTotalBucketCount() -} - -func (s *contractStakingCacheThreadSafety) getTotalBucketTypeCount() uint64 { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getTotalBucketTypeCount() -} - -func (s *contractStakingCacheThreadSafety) getAllBucketInfo() map[uint64]*ContractStakingBucketInfo { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getAllBucketInfo() -} - -func (s *contractStakingCacheThreadSafety) getActiveBucketType() map[uint64]*ContractStakingBucketType { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getActiveBucketType() -} - -func (s *contractStakingCacheThreadSafety) getBucketInfoByCandidate(candidate address.Address) map[uint64]*ContractStakingBucketInfo { - s.mutex.RLock() - defer s.mutex.RUnlock() - - return s.cache.getBucketInfoByCandidate(candidate) -} - -func (s *contractStakingCacheThreadSafety) merge(delta *contractStakingDelta) error { - s.mutex.Lock() - defer s.mutex.Unlock() - - return s.cache.merge(delta) -} - -func (s *contractStakingCacheThreadSafety) unsafe() contractStakingCacheManager { - return s.cache -} diff --git a/blockindex/liquidstaking_cache_test.go b/blockindex/liquidstaking_cache_test.go deleted file mode 100644 index 1872f7debd..0000000000 --- a/blockindex/liquidstaking_cache_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2023 IoTeX Foundation -// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability -// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. -// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. - -package blockindex - -import ( - "math/big" - "sync" - "testing" -) - -func TestContractStakingCacheThreadSafety(t *testing.T) { - cache := newContractStakingCache() - - wait := sync.WaitGroup{} - wait.Add(2) - go func() { - for i := 0; i < 1000; i++ { - cache.putBucketType(uint64(i), &ContractStakingBucketType{ - Amount: big.NewInt(int64(i)), - Duration: 1000, - ActivatedAt: 10, - }) - } - wait.Done() - }() - - go func() { - for i := 0; i < 1000; i++ { - cache.getBucketType(uint64(i)) - } - wait.Done() - }() - - wait.Wait() - // no panic means thread safety -} diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 832a95109d..d411613b26 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -405,9 +405,9 @@ type ( // cache: in-memory index for clean data, used to query index data // dirty: the cache to update during event processing, will be merged to clean cache after all events are processed. If errors occur during event processing, dirty cache will be discarded. contractStakingIndexer struct { - kvstore db.KVStore // persistent storage - cache *contractStakingCacheThreadSafety // in-memory index for clean data - mutex sync.RWMutex // mutex for multiple reading to cache + kvstore db.KVStore // persistent storage + cache contractStakingCacheManager // in-memory index for clean data + mutex sync.RWMutex // mutex for multiple reading to cache } ) @@ -448,6 +448,9 @@ func (s *contractStakingIndexer) Start(ctx context.Context) error { // Stop stops the indexer func (s *contractStakingIndexer) Stop(ctx context.Context) error { + s.mutex.Lock() + defer s.mutex.Unlock() + if err := s.kvstore.Stop(ctx); err != nil { return err } @@ -460,7 +463,7 @@ func (s *contractStakingIndexer) PutBlock(ctx context.Context, blk *block.Block) // new dirty cache for this block // it's not necessary to use thread safe cache here, because only one thread will call this function // and no update to cache will happen before dirty merge to clean - dirty := newContractStakingDirty(s.cache.unsafe()) + dirty := newContractStakingDirty(s.cache) dirty.putHeight(blk.Height()) // handle events of block @@ -489,11 +492,15 @@ func (s *contractStakingIndexer) DeleteTipBlock(context.Context, *block.Block) e // Height returns the tip block height func (s *contractStakingIndexer) Height() (uint64, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() return s.cache.getHeight(), nil } // CandidateVotes returns the candidate votes func (s *contractStakingIndexer) CandidateVotes(candidate address.Address) *big.Int { + s.mutex.RLock() + defer s.mutex.RUnlock() return s.cache.getCandidateVotes(candidate) } @@ -554,10 +561,14 @@ func (s *contractStakingIndexer) BucketsByCandidate(candidate address.Address) ( } func (s *contractStakingIndexer) TotalBucketCount() uint64 { + s.mutex.RLock() + defer s.mutex.RUnlock() return s.cache.getTotalBucketCount() } func (s *contractStakingIndexer) ActiveBucketTypes() (map[uint64]*ContractStakingBucketType, error) { + s.mutex.RLock() + defer s.mutex.RUnlock() return s.cache.getActiveBucketType(), nil } From 48962439ad6f2f118264d40cf7544f83fecbbbc5 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 22:26:17 +0800 Subject: [PATCH 48/51] add test & fix --- blockindex/liquidstaking_dirty.go | 6 +- blockindex/liquidstaking_indexer.go | 4 +- blockindex/liquidstaking_indexer_test.go | 84 ++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 blockindex/liquidstaking_indexer_test.go diff --git a/blockindex/liquidstaking_dirty.go b/blockindex/liquidstaking_dirty.go index 26e40f96f5..63921eca68 100644 --- a/blockindex/liquidstaking_dirty.go +++ b/blockindex/liquidstaking_dirty.go @@ -200,10 +200,14 @@ func (dirty *contractStakingDirty) handleStakedEvent(event eventParam, height ui if !ok { return errors.Wrapf(errBucketTypeNotExist, "amount %d, duration %d", amountParam.Int64(), durationParam.Uint64()) } + owner, ok := dirty.tokenOwner[tokenIDParam.Uint64()] + if !ok { + return errors.Errorf("no owner for token id %d", tokenIDParam.Uint64()) + } bucket := ContractStakingBucketInfo{ TypeIndex: btIdx, Delegate: delegateParam, - Owner: dirty.tokenOwner[tokenIDParam.Uint64()], + Owner: owner, CreatedAt: height, UnlockedAt: maxBlockNumber, UnstakedAt: maxBlockNumber, diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index d411613b26..89d28421cf 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -663,7 +663,7 @@ func (s *contractStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - delta.putBucketInfo(byteutil.BytesToUint64BigEndian(ks[i]), &b) + delta.addBucketInfo(byteutil.BytesToUint64BigEndian(ks[i]), &b) } // load bucket type @@ -676,7 +676,7 @@ func (s *contractStakingIndexer) loadCache() error { if err := b.deserialize(vs[i]); err != nil { return err } - delta.putBucketType(byteutil.BytesToUint64BigEndian(ks[i]), &b) + delta.addBucketType(byteutil.BytesToUint64BigEndian(ks[i]), &b) } return s.cache.merge(delta) } diff --git a/blockindex/liquidstaking_indexer_test.go b/blockindex/liquidstaking_indexer_test.go new file mode 100644 index 0000000000..2981f15a6a --- /dev/null +++ b/blockindex/liquidstaking_indexer_test.go @@ -0,0 +1,84 @@ +// Copyright (c) 2023 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package blockindex + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/iotexproject/iotex-core/db" + "github.com/iotexproject/iotex-core/test/identityset" + "github.com/iotexproject/iotex-core/testutil" +) + +func TestContractStakingIndexerLoadCache(t *testing.T) { + r := require.New(t) + testDBPath, err := testutil.PathOfTempFile("staking.db") + r.NoError(err) + defer testutil.CleanupPath(testDBPath) + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + indexer := &contractStakingIndexer{ + kvstore: kvStore, + cache: newContractStakingCache(), + } + r.NoError(indexer.Start(context.Background())) + + // create a stake + dirty := newContractStakingDirty(indexer.cache) + height := uint64(1) + dirty.putHeight(height) + err = dirty.handleBucketTypeActivatedEvent(eventParam{ + "amount": big.NewInt(10), + "duration": big.NewInt(100), + }, height) + r.NoError(err) + owner := identityset.Address(0) + + err = dirty.handleTransferEvent(eventParam{ + "to": common.BytesToAddress(owner.Bytes()), + "tokenId": big.NewInt(1), + }) + r.NoError(err) + delegate := identityset.Address(1) + err = dirty.handleStakedEvent(eventParam{ + "tokenId": big.NewInt(1), + "delegate": common.BytesToAddress(delegate.Bytes()), + "amount": big.NewInt(10), + "duration": big.NewInt(100), + }, height) + r.NoError(err) + err = indexer.commit(dirty) + r.NoError(err) + buckets, err := indexer.Buckets() + r.NoError(err) + r.NoError(indexer.Stop(context.Background())) + + // load cache from db + newIndexer := &contractStakingIndexer{ + kvstore: db.NewBoltDB(cfg), + cache: newContractStakingCache(), + } + r.NoError(newIndexer.Start(context.Background())) + + // check cache + newBuckets, err := newIndexer.Buckets() + r.NoError(err) + r.Equal(len(buckets), len(newBuckets)) + for i := range buckets { + r.EqualValues(buckets[i], newBuckets[i]) + } + newHeight, err := newIndexer.Height() + r.NoError(err) + r.Equal(height, newHeight) + r.EqualValues(1, newIndexer.TotalBucketCount()) + r.NoError(newIndexer.Stop(context.Background())) +} From 1cc71b94d3b07f1d1cb8f704a34ed369a8a244b8 Mon Sep 17 00:00:00 2001 From: envestcc Date: Thu, 18 May 2023 23:52:07 +0800 Subject: [PATCH 49/51] add tests --- blockindex/liquidstaking_bucket.go | 2 +- blockindex/liquidstaking_indexer_test.go | 384 +++++++++++++++++++++-- 2 files changed, 367 insertions(+), 19 deletions(-) diff --git a/blockindex/liquidstaking_bucket.go b/blockindex/liquidstaking_bucket.go index ad4da0ecaa..771e9c0687 100644 --- a/blockindex/liquidstaking_bucket.go +++ b/blockindex/liquidstaking_bucket.go @@ -18,7 +18,7 @@ import ( ) const ( - maxBlockNumber = math.MaxUint64 + maxBlockNumber uint64 = math.MaxUint64 ) type ( diff --git a/blockindex/liquidstaking_indexer_test.go b/blockindex/liquidstaking_indexer_test.go index 2981f15a6a..1084b18d65 100644 --- a/blockindex/liquidstaking_indexer_test.go +++ b/blockindex/liquidstaking_indexer_test.go @@ -8,11 +8,14 @@ package blockindex import ( "context" "math/big" + "sync" "testing" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/iotexproject/iotex-address/address" + "github.com/iotexproject/iotex-core/db" "github.com/iotexproject/iotex-core/test/identityset" "github.com/iotexproject/iotex-core/testutil" @@ -36,26 +39,10 @@ func TestContractStakingIndexerLoadCache(t *testing.T) { dirty := newContractStakingDirty(indexer.cache) height := uint64(1) dirty.putHeight(height) - err = dirty.handleBucketTypeActivatedEvent(eventParam{ - "amount": big.NewInt(10), - "duration": big.NewInt(100), - }, height) - r.NoError(err) + activateBucketType(r, dirty, 10, 100, height) owner := identityset.Address(0) - - err = dirty.handleTransferEvent(eventParam{ - "to": common.BytesToAddress(owner.Bytes()), - "tokenId": big.NewInt(1), - }) - r.NoError(err) delegate := identityset.Address(1) - err = dirty.handleStakedEvent(eventParam{ - "tokenId": big.NewInt(1), - "delegate": common.BytesToAddress(delegate.Bytes()), - "amount": big.NewInt(10), - "duration": big.NewInt(100), - }, height) - r.NoError(err) + stake(r, dirty, owner, delegate, 1, 10, 100, height) err = indexer.commit(dirty) r.NoError(err) buckets, err := indexer.Buckets() @@ -82,3 +69,364 @@ func TestContractStakingIndexerLoadCache(t *testing.T) { r.EqualValues(1, newIndexer.TotalBucketCount()) r.NoError(newIndexer.Stop(context.Background())) } + +func TestContractStakingIndexerDirty(t *testing.T) { + r := require.New(t) + testDBPath, err := testutil.PathOfTempFile("staking.db") + r.NoError(err) + defer testutil.CleanupPath(testDBPath) + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + indexer := &contractStakingIndexer{ + kvstore: kvStore, + cache: newContractStakingCache(), + } + r.NoError(indexer.Start(context.Background())) + + // before commit dirty, the cache should be empty + dirty := newContractStakingDirty(indexer.cache) + height := uint64(1) + dirty.putHeight(height) + gotHeight, err := indexer.Height() + r.NoError(err) + r.EqualValues(0, gotHeight) + // after commit dirty, the cache should be updated + err = indexer.commit(dirty) + r.NoError(err) + gotHeight, err = indexer.Height() + r.NoError(err) + r.EqualValues(height, gotHeight) + + r.NoError(indexer.Stop(context.Background())) +} + +func TestContractStakingIndexerThreadSafe(t *testing.T) { + r := require.New(t) + testDBPath, err := testutil.PathOfTempFile("staking.db") + r.NoError(err) + defer testutil.CleanupPath(testDBPath) + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + indexer := &contractStakingIndexer{ + kvstore: kvStore, + cache: newContractStakingCache(), + } + r.NoError(indexer.Start(context.Background())) + + wait := sync.WaitGroup{} + wait.Add(6) + owner := identityset.Address(0) + delegate := identityset.Address(1) + // read concurrently + for i := 0; i < 5; i++ { + go func() { + defer wait.Done() + for i := 0; i < 1000; i++ { + _, err := indexer.Buckets() + r.NoError(err) + _, err = indexer.ActiveBucketTypes() + r.NoError(err) + _, err = indexer.BucketsByCandidate(delegate) + r.NoError(err) + indexer.CandidateVotes(delegate) + _, err = indexer.Height() + r.NoError(err) + indexer.TotalBucketCount() + } + }() + } + // write + go func() { + defer wait.Done() + // activate bucket type + dirty := newContractStakingDirty(indexer.cache) + activateBucketType(r, dirty, 10, 100, 1) + r.NoError(indexer.commit(dirty)) + for i := 2; i < 1000; i++ { + dirty := newContractStakingDirty(indexer.cache) + height := uint64(i) + dirty.putHeight(height) + stake(r, dirty, owner, delegate, 1, 10, 100, height) + err := indexer.commit(dirty) + r.NoError(err) + } + }() + wait.Wait() + r.NoError(indexer.Stop(context.Background())) + // no panic means thread safe +} + +func TestContractStakingIndexerBucketType(t *testing.T) { + r := require.New(t) + testDBPath, err := testutil.PathOfTempFile("staking.db") + r.NoError(err) + defer testutil.CleanupPath(testDBPath) + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + indexer := &contractStakingIndexer{ + kvstore: kvStore, + cache: newContractStakingCache(), + } + r.NoError(indexer.Start(context.Background())) + + // activate + bucketTypeData := [][2]int64{ + {10, 10}, + {20, 10}, + {10, 100}, + {20, 100}, + } + height := uint64(1) + dirty := newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + for _, data := range bucketTypeData { + activateBucketType(r, dirty, data[0], data[1], height) + } + err = indexer.commit(dirty) + r.NoError(err) + bucketTypes, err := indexer.ActiveBucketTypes() + r.NoError(err) + r.Equal(len(bucketTypeData), len(bucketTypes)) + for i, data := range bucketTypeData { + r.EqualValues(data[0], bucketTypes[uint64(i)].Amount.Int64()) + r.EqualValues(data[1], bucketTypes[uint64(i)].Duration) + r.EqualValues(height, bucketTypes[uint64(i)].ActivatedAt) + } + // deactivate + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + for i := 0; i < 2; i++ { + data := bucketTypeData[i] + deactivateBucketType(r, dirty, data[0], data[1], height) + } + err = indexer.commit(dirty) + r.NoError(err) + bucketTypes, err = indexer.ActiveBucketTypes() + r.NoError(err) + r.Equal(len(bucketTypeData)-2, len(bucketTypes)) + for i, data := range bucketTypeData { + if i < 2 { + continue + } + r.EqualValues(data[0], bucketTypes[uint64(i)].Amount.Int64()) + r.EqualValues(data[1], bucketTypes[uint64(i)].Duration) + r.EqualValues(1, bucketTypes[uint64(i)].ActivatedAt) + } + // reactivate + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + for i := 0; i < 2; i++ { + data := bucketTypeData[i] + activateBucketType(r, dirty, data[0], data[1], height) + } + err = indexer.commit(dirty) + r.NoError(err) + bucketTypes, err = indexer.ActiveBucketTypes() + r.NoError(err) + r.Equal(len(bucketTypeData), len(bucketTypes)) + for i, data := range bucketTypeData { + r.EqualValues(data[0], bucketTypes[uint64(i)].Amount.Int64()) + r.EqualValues(data[1], bucketTypes[uint64(i)].Duration) + if i < 2 { + r.EqualValues(height, bucketTypes[uint64(i)].ActivatedAt) + } else { + r.EqualValues(1, bucketTypes[uint64(i)].ActivatedAt) + } + } + r.NoError(indexer.Stop(context.Background())) +} + +func TestContractStakingIndexerBucketInfo(t *testing.T) { + r := require.New(t) + testDBPath, err := testutil.PathOfTempFile("staking.db") + r.NoError(err) + defer testutil.CleanupPath(testDBPath) + cfg := db.DefaultConfig + cfg.DbPath = testDBPath + kvStore := db.NewBoltDB(cfg) + indexer := &contractStakingIndexer{ + kvstore: kvStore, + cache: newContractStakingCache(), + } + r.NoError(indexer.Start(context.Background())) + + // init bucket type + bucketTypeData := [][2]int64{ + {10, 10}, + {20, 10}, + {10, 100}, + {20, 100}, + } + height := uint64(1) + dirty := newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + for _, data := range bucketTypeData { + activateBucketType(r, dirty, data[0], data[1], height) + } + err = indexer.commit(dirty) + r.NoError(err) + + // stake + owner := identityset.Address(0) + delegate := identityset.Address(1) + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + stake(r, dirty, owner, delegate, 1, 10, 100, height) + r.NoError(err) + r.NoError(indexer.commit(dirty)) + bucket, err := indexer.Bucket(1) + r.NoError(err) + r.EqualValues(1, bucket.Index) + r.EqualValues(owner, bucket.Owner) + r.EqualValues(delegate, bucket.Candidate) + r.EqualValues(10, bucket.StakedAmount.Int64()) + r.EqualValues(100, bucket.StakedDurationBlockNumber) + r.EqualValues(height, bucket.StakeBlockHeight) + r.True(bucket.AutoStake) + r.EqualValues(height, bucket.CreateBlockHeight) + r.EqualValues(maxBlockNumber, bucket.UnstakeBlockHeight) + r.EqualValues(StakingContractAddress, bucket.ContractAddress) + r.EqualValues(10, indexer.CandidateVotes(delegate).Uint64()) + r.EqualValues(1, indexer.TotalBucketCount()) + + // unlock + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + unlock(r, dirty, int64(bucket.Index), height) + r.NoError(indexer.commit(dirty)) + bucket, err = indexer.Bucket(bucket.Index) + r.NoError(err) + r.EqualValues(1, bucket.Index) + r.EqualValues(owner, bucket.Owner) + r.EqualValues(delegate, bucket.Candidate) + r.EqualValues(10, bucket.StakedAmount.Int64()) + r.EqualValues(100, bucket.StakedDurationBlockNumber) + r.EqualValues(height, bucket.StakeBlockHeight) + r.False(bucket.AutoStake) + r.EqualValues(height-1, bucket.CreateBlockHeight) + r.EqualValues(maxBlockNumber, bucket.UnstakeBlockHeight) + r.EqualValues(StakingContractAddress, bucket.ContractAddress) + r.EqualValues(10, indexer.CandidateVotes(delegate).Uint64()) + r.EqualValues(1, indexer.TotalBucketCount()) + + // lock again + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + lock(r, dirty, int64(bucket.Index), int64(10)) + r.NoError(indexer.commit(dirty)) + bucket, err = indexer.Bucket(bucket.Index) + r.NoError(err) + r.EqualValues(1, bucket.Index) + r.EqualValues(owner, bucket.Owner) + r.EqualValues(delegate, bucket.Candidate) + r.EqualValues(10, bucket.StakedAmount.Int64()) + r.EqualValues(10, bucket.StakedDurationBlockNumber) + r.EqualValues(height-2, bucket.StakeBlockHeight) + r.True(bucket.AutoStake) + r.EqualValues(height-2, bucket.CreateBlockHeight) + r.EqualValues(maxBlockNumber, bucket.UnstakeBlockHeight) + r.EqualValues(StakingContractAddress, bucket.ContractAddress) + r.EqualValues(10, indexer.CandidateVotes(delegate).Uint64()) + r.EqualValues(1, indexer.TotalBucketCount()) + + // unstake + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + unlock(r, dirty, int64(bucket.Index), height) + unstake(r, dirty, int64(bucket.Index), height) + r.NoError(indexer.commit(dirty)) + bucket, err = indexer.Bucket(bucket.Index) + r.NoError(err) + r.EqualValues(1, bucket.Index) + r.EqualValues(owner, bucket.Owner) + r.EqualValues(delegate, bucket.Candidate) + r.EqualValues(10, bucket.StakedAmount.Int64()) + r.EqualValues(10, bucket.StakedDurationBlockNumber) + r.EqualValues(height, bucket.StakeBlockHeight) + r.False(bucket.AutoStake) + r.EqualValues(height-3, bucket.CreateBlockHeight) + r.EqualValues(height, bucket.UnstakeBlockHeight) + r.EqualValues(StakingContractAddress, bucket.ContractAddress) + r.EqualValues(0, indexer.CandidateVotes(delegate).Uint64()) + r.EqualValues(1, indexer.TotalBucketCount()) + + // withdraw + height++ + dirty = newContractStakingDirty(indexer.cache) + dirty.putHeight(height) + withdraw(r, dirty, int64(bucket.Index)) + r.NoError(indexer.commit(dirty)) + bucket, err = indexer.Bucket(bucket.Index) + r.ErrorIs(err, ErrBucketInfoNotExist) + r.EqualValues(0, indexer.CandidateVotes(delegate).Uint64()) + r.EqualValues(1, indexer.TotalBucketCount()) +} + +func activateBucketType(r *require.Assertions, dirty *contractStakingDirty, amount, duration int64, height uint64) { + err := dirty.handleBucketTypeActivatedEvent(eventParam{ + "amount": big.NewInt(amount), + "duration": big.NewInt(duration), + }, height) + r.NoError(err) +} + +func deactivateBucketType(r *require.Assertions, dirty *contractStakingDirty, amount, duration int64, height uint64) { + err := dirty.handleBucketTypeDeactivatedEvent(eventParam{ + "amount": big.NewInt(amount), + "duration": big.NewInt(duration), + }, height) + r.NoError(err) +} + +func stake(r *require.Assertions, dirty *contractStakingDirty, owner, candidate address.Address, token, amount, duration int64, height uint64) { + err := dirty.handleTransferEvent(eventParam{ + "to": common.BytesToAddress(owner.Bytes()), + "tokenId": big.NewInt(token), + }) + r.NoError(err) + err = dirty.handleStakedEvent(eventParam{ + "tokenId": big.NewInt(token), + "delegate": common.BytesToAddress(candidate.Bytes()), + "amount": big.NewInt(amount), + "duration": big.NewInt(duration), + }, height) + r.NoError(err) +} + +func unlock(r *require.Assertions, dirty *contractStakingDirty, token int64, height uint64) { + err := dirty.handleUnlockedEvent(eventParam{ + "tokenId": big.NewInt(token), + }, height) + r.NoError(err) +} + +func lock(r *require.Assertions, dirty *contractStakingDirty, token, duration int64) { + err := dirty.handleLockedEvent(eventParam{ + "tokenId": big.NewInt(token), + "duration": big.NewInt(duration), + }) + r.NoError(err) +} + +func unstake(r *require.Assertions, dirty *contractStakingDirty, token int64, height uint64) { + err := dirty.handleUnstakedEvent(eventParam{ + "tokenId": big.NewInt(token), + }, height) + r.NoError(err) +} + +func withdraw(r *require.Assertions, dirty *contractStakingDirty, token int64) { + err := dirty.handleWithdrawalEvent(eventParam{ + "tokenId": big.NewInt(token), + }) + r.NoError(err) +} From 84e8da0ffeba2ac3a360f318cad961a2b139803e Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 19 May 2023 00:04:11 +0800 Subject: [PATCH 50/51] return error when received enexpected event --- blockindex/liquidstaking_indexer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 89d28421cf..2616569b89 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -620,8 +620,11 @@ func (s *contractStakingIndexer) handleEvent(ctx context.Context, dirty *contrac return dirty.handleWithdrawalEvent(event) case "Transfer": return dirty.handleTransferEvent(event) - default: + case "Approval", "ApprovalForAll", "OwnershipTransferred", "Paused", "Unpaused": + // not require handling events return nil + default: + return errors.Errorf("unknown event name %s", abiEvent.Name) } } From 43867a4933e8907dd0963a740fdf6b44c8156d57 Mon Sep 17 00:00:00 2001 From: envestcc Date: Fri, 19 May 2023 00:25:22 +0800 Subject: [PATCH 51/51] acid for commit --- blockindex/liquidstaking_indexer.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/blockindex/liquidstaking_indexer.go b/blockindex/liquidstaking_indexer.go index 2616569b89..08d60c08e0 100644 --- a/blockindex/liquidstaking_indexer.go +++ b/blockindex/liquidstaking_indexer.go @@ -628,6 +628,11 @@ func (s *contractStakingIndexer) handleEvent(ctx context.Context, dirty *contrac } } +func (s *contractStakingIndexer) reloadCache() error { + s.cache = newContractStakingCache() + return s.loadCache() +} + func (s *contractStakingIndexer) loadCache() error { delta := newContractStakingDelta() // load height @@ -689,10 +694,12 @@ func (s *contractStakingIndexer) commit(dirty *contractStakingDirty) error { defer s.mutex.Unlock() batch, delta := dirty.finalize() - if err := s.kvstore.WriteBatch(batch); err != nil { + if err := s.cache.merge(delta); err != nil { + s.reloadCache() return err } - if err := s.cache.merge(delta); err != nil { + if err := s.kvstore.WriteBatch(batch); err != nil { + s.reloadCache() return err } return nil