From 84e20fb99b891174c5a96fbc2baf0322bf5d314f Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Fri, 8 May 2020 14:42:02 +0300 Subject: [PATCH 01/79] EN-6373 : add test for ComputeEndOfEpochEconomics --- epochStart/metachain/economics_test.go | 156 +++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/epochStart/metachain/economics_test.go b/epochStart/metachain/economics_test.go index 16c76c691b..a8b4c436ef 100644 --- a/epochStart/metachain/economics_test.go +++ b/epochStart/metachain/economics_test.go @@ -2,6 +2,7 @@ package metachain import ( "encoding/json" + "fmt" "math/big" "testing" "time" @@ -442,6 +443,161 @@ func TestEconomics_VerifyRewardsPerBlock_DifferentHitRates(t *testing.T) { } } +func TestComputeEndOfEpochEconomics(t *testing.T) { + t.Parallel() + + commAddress := "communityAddress" + totalSupply, _ := big.NewInt(0).SetString("20000000000000000000000000000", 10) // 20 Billions ERD + nodePrice, _ := big.NewInt(0).SetString("1000000000000000000000", 10) // 1000 ERD + + roundDur := 4 + args := getArguments() + args.RewardsHandler = &mock.RewardsHandlerStub{ + MaxInflationRateCalled: func() float64 { + return 0.1 + }, + CommunityAddressCalled: func() string { + return commAddress + }, + CommunityPercentageCalled: func() float64 { + return 0.1 + }, + LeaderPercentageCalled: func() float64 { + return 0.1 + }, + } + args.RoundTime = &mock.RoundTimeDurationHandler{ + TimeDurationCalled: func() time.Duration { + return time.Duration(roundDur) * time.Second + }, + } + hdrPrevEpochStart := block.MetaBlock{ + Round: 0, + Nonce: 0, + Epoch: 0, + EpochStart: block.EpochStart{ + Economics: block.Economics{ + TotalSupply: totalSupply, + TotalToDistribute: big.NewInt(10), + TotalNewlyMinted: big.NewInt(10), + RewardsPerBlockPerNode: big.NewInt(10), + NodePrice: nodePrice, + RewardsForCommunity: big.NewInt(10), + }, + LastFinalizedHeaders: []block.EpochStartShardData{ + {ShardID: 0, Nonce: 0}, + {ShardID: 1, Nonce: 0}, + }, + }, + } + args.Store = &mock.ChainStorerStub{ + GetStorerCalled: func(unitType dataRetriever.UnitType) storage.Storer { + // this will be the previous epoch meta block. It has initial 0 values so it can be considered at genesis + return &mock.StorerStub{GetCalled: func(key []byte) ([]byte, error) { + hdrBytes, _ := json.Marshal(hdrPrevEpochStart) + return hdrBytes, nil + }} + }, + } + + ec, _ := NewEndOfEpochEconomicsDataCreator(args) + + epochDuration := numberOfSecondsInDay + roundsPerEpoch := uint64(epochDuration / roundDur) + type testInput struct { + blockPerEpochOneShard uint64 + acFeesInEpoch *big.Int + devFeesInEpoch *big.Int + } + + testInpus := []testInput{ + {blockPerEpochOneShard: roundsPerEpoch, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 2, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 4, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 8, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 16, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 32, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 64, acFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(10000000)}, + {blockPerEpochOneShard: roundsPerEpoch, acFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(30000000000000)}, + } + + rewardsPerBlock, _ := big.NewInt(0).SetString("84559445290038908043", 10) // *based on 0.1 inflation + for _, input := range testInpus { + meta := &block.MetaBlock{ + AccumulatedFeesInEpoch: input.acFeesInEpoch, + DevFeesInEpoch: input.devFeesInEpoch, + Epoch: 1, + Round: roundsPerEpoch, + Nonce: input.blockPerEpochOneShard, + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + {ShardID: 0, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, + {ShardID: 1, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, + }, + }, + } + + economicsBlock, err := ec.ComputeEndOfEpochEconomics(meta) + assert.Nil(t, err) + + blocksPerEpochTotal := int64(input.blockPerEpochOneShard * 3) + hitRate := float64(input.blockPerEpochOneShard) / float64(roundsPerEpoch) * 100 + printEconomicsData(economicsBlock, hitRate, blocksPerEpochTotal) + + expectedTotalRewardsToBeDistributed := big.NewInt(0).Mul(rewardsPerBlock, big.NewInt(blocksPerEpochTotal)) + expectedNewTokens := big.NewInt(0).Sub(expectedTotalRewardsToBeDistributed, input.acFeesInEpoch) + if expectedNewTokens.Cmp(big.NewInt(0)) < 0 { + expectedNewTokens = big.NewInt(0) + expectedTotalRewardsToBeDistributed = input.acFeesInEpoch + } + + adjustedRewardsPerBlock := big.NewInt(0).Div(expectedTotalRewardsToBeDistributed, big.NewInt(blocksPerEpochTotal)) + + // subtract developer rewards per block + developerFeesPerBlock := big.NewInt(0).Div(input.devFeesInEpoch, big.NewInt(blocksPerEpochTotal)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, developerFeesPerBlock) + // subtract leader percentage per block + rewardsForLeader := core.GetPercentageOfValue(input.acFeesInEpoch, args.RewardsHandler.LeaderPercentage()) + rewardsForLeaderPerBlock := big.NewInt(0).Div(rewardsForLeader, big.NewInt(blocksPerEpochTotal)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, rewardsForLeaderPerBlock) + // communityPercentage + expectedCommunityRewards := core.GetPercentageOfValue(expectedTotalRewardsToBeDistributed, args.RewardsHandler.CommunityPercentage()) + // subtract community percentage per block + communityRewardsPerBlock := big.NewInt(0).Div(expectedCommunityRewards, big.NewInt(blocksPerEpochTotal)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, communityRewardsPerBlock) + + assert.Equal(t, expectedNewTokens, economicsBlock.TotalNewlyMinted) + assert.Equal(t, big.NewInt(0).Add(totalSupply, expectedNewTokens), economicsBlock.TotalSupply) + assert.Equal(t, expectedTotalRewardsToBeDistributed, economicsBlock.TotalToDistribute) + assert.Equal(t, expectedCommunityRewards, economicsBlock.RewardsForCommunity) + assert.Equal(t, nodePrice, economicsBlock.NodePrice) + assert.Equal(t, adjustedRewardsPerBlock, economicsBlock.RewardsPerBlockPerNode) + } + +} + +func printEconomicsData(eb *block.Economics, hitRate float64, numBlocksTotal int64) { + fmt.Printf("Hit rate per shard %.4f%%, Total block produced: %d \n", hitRate, numBlocksTotal) + fmt.Printf("Total supply: %vERD, TotalToDistribute %vERD, "+ + "TotalNewlyMinted %vERD, RewardsPerBlockPerNode %vERD, RewardsForCommunity %vERD, NodePrice: %vERD", + denomination(eb.TotalSupply), denomination(eb.TotalToDistribute), denomination(eb.TotalNewlyMinted), + denomination(eb.RewardsPerBlockPerNode), denomination(eb.RewardsForCommunity), denomination(eb.NodePrice)) + fmt.Println() +} + +func intToErd(value int) *big.Int { + denomination, _ := big.NewInt(0).SetString("1000000000000000000", 10) + + return big.NewInt(0).Mul(denomination, big.NewInt(int64(value))) +} + +func denomination(value *big.Int) string { + denomination, _ := big.NewInt(0).SetString("1000000000000000000", 10) + cpValue := big.NewInt(0).Set(value) + + return cpValue.Div(cpValue, denomination).String() +} + func getArguments() ArgsNewEpochEconomics { return ArgsNewEpochEconomics{ Marshalizer: &mock.MarshalizerMock{}, From 2586fec178783a4842c8f58fcf3774938307736e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 13:39:07 +0300 Subject: [PATCH 02/79] Remove eviction phase 1 (not necessary). --- storage/txcache/config.go | 4 +- storage/txcache/eviction.go | 42 +------------- storage/txcache/eviction_test.go | 73 ++----------------------- storage/txcache/monitoring.go | 7 +-- storage/txcache/txCache_test.go | 4 -- storage/txcache/txListForSender.go | 25 --------- storage/txcache/txListForSender_test.go | 31 ----------- 7 files changed, 11 insertions(+), 175 deletions(-) diff --git a/storage/txcache/config.go b/storage/txcache/config.go index cdd29d7295..b4b4638e2b 100644 --- a/storage/txcache/config.go +++ b/storage/txcache/config.go @@ -6,9 +6,9 @@ type CacheConfig struct { NumChunksHint uint32 EvictionEnabled bool NumBytesThreshold uint32 + NumBytesPerSenderThreshold uint32 CountThreshold uint32 + CountPerSenderThreshold uint32 NumSendersToEvictInOneStep uint32 - LargeNumOfTxsForASender uint32 - NumTxsToEvictFromASender uint32 MinGasPriceMicroErd uint32 } diff --git a/storage/txcache/eviction.go b/storage/txcache/eviction.go index 2ddede3e29..cf7e861435 100644 --- a/storage/txcache/eviction.go +++ b/storage/txcache/eviction.go @@ -30,15 +30,9 @@ func (cache *TxCache) doEviction() { stopWatch := cache.monitorEvictionStart() - if tooManyTxs { - cache.makeSnapshotOfSenders() - journal.passOneNumTxs, journal.passOneNumSenders = cache.evictHighNonceTransactions() - journal.evictionPerformed = true - } - if cache.shouldContinueEvictingSenders() { cache.makeSnapshotOfSenders() - journal.passTwoNumSteps, journal.passTwoNumTxs, journal.passTwoNumSenders = cache.evictSendersInLoop() + journal.passOneNumSteps, journal.passOneNumTxs, journal.passOneNumSenders = cache.evictSendersInLoop() journal.evictionPerformed = true } @@ -77,40 +71,6 @@ func (cache *TxCache) shouldContinueEvictingSenders() bool { return cache.areThereTooManyTxs() || cache.areThereTooManySenders() || cache.areThereTooManyBytes() } -// evictHighNonceTransactions removes transactions from the cache -// For senders with many transactions (> "LargeNumOfTxsForASender"), evict "NumTxsToEvictFromASender" transactions -// Also makes sure that there's no sender with 0 transactions -func (cache *TxCache) evictHighNonceTransactions() (uint32, uint32) { - threshold := cache.config.LargeNumOfTxsForASender - numTxsToEvict := cache.config.NumTxsToEvictFromASender - - // Heuristics: estimate that ~10% of senders have more transactions than the threshold - sendersToEvictInitialCapacity := len(cache.evictionSnapshotOfSenders)/10 + 1 - txsToEvictInitialCapacity := sendersToEvictInitialCapacity * int(numTxsToEvict) - - sendersToEvict := make([]string, 0, sendersToEvictInitialCapacity) - txsToEvict := make([][]byte, 0, txsToEvictInitialCapacity) - - for _, txList := range cache.evictionSnapshotOfSenders { - if txList.HasMoreThan(threshold) { - txsToEvictForSender := txList.RemoveHighNonceTxs(numTxsToEvict) - txsToEvict = append(txsToEvict, txsToEvictForSender...) - } - - if txList.IsEmpty() { - sendersToEvict = append(sendersToEvict, txList.sender) - } - } - - // Note that, at this very moment, high nonce transactions have been evicted from senders' lists, - // but not yet from the map of transactions. - // - // This may cause slight inconsistencies, such as: - // - if a tx previously (recently) removed from the sender's list ("RemoveHighNonceTxs") arrives again at the pool, - // before the execution of "doEvictItems", the tx will be ignored as it still exists (for a short time) in the map of transactions. - return cache.doEvictItems(txsToEvict, sendersToEvict) -} - // This is called concurrently by two goroutines: the eviction one and the sweeping one func (cache *TxCache) doEvictItems(txsToEvict [][]byte, sendersToEvict []string) (countTxs uint32, countSenders uint32) { countTxs = cache.txByHash.RemoveTxsBulk(txsToEvict) diff --git a/storage/txcache/eviction_test.go b/storage/txcache/eviction_test.go index 7f22906285..f4acf5a3f2 100644 --- a/storage/txcache/eviction_test.go +++ b/storage/txcache/eviction_test.go @@ -9,61 +9,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestEviction_EvictHighNonceTransactions(t *testing.T) { - config := CacheConfig{ - NumChunksHint: 16, - CountThreshold: 400, - LargeNumOfTxsForASender: 50, - NumTxsToEvictFromASender: 25, - MinGasPriceMicroErd: 100, - } - - cache := NewTxCache(config) - - for index := 0; index < 200; index++ { - cache.AddTx(createTx([]byte{'a', byte(index)}, "alice", uint64(index))) - } - - for index := 0; index < 200; index++ { - cache.AddTx(createTx([]byte{'b', byte(index)}, "bob", uint64(index))) - } - - cache.AddTx(createTx([]byte("hash-carol"), "carol", uint64(1))) - - require.Equal(t, int64(3), cache.txListBySender.counter.Get()) - require.Equal(t, int64(401), cache.txByHash.counter.Get()) - - cache.makeSnapshotOfSenders() - nTxs, nSenders := cache.evictHighNonceTransactions() - - require.Equal(t, uint32(50), nTxs) - require.Equal(t, uint32(0), nSenders) - require.Equal(t, int64(3), cache.txListBySender.counter.Get()) - require.Equal(t, int64(351), cache.txByHash.counter.Get()) -} - -func TestEviction_EvictHighNonceTransactions_CoverEmptiedSenderList(t *testing.T) { - config := CacheConfig{ - NumChunksHint: 1, - CountThreshold: 0, - LargeNumOfTxsForASender: 0, - NumTxsToEvictFromASender: 1, - MinGasPriceMicroErd: 100, - } - - cache := NewTxCache(config) - cache.AddTx(createTx([]byte("hash-alice"), "alice", uint64(1))) - require.Equal(t, int64(1), cache.CountSenders()) - - cache.makeSnapshotOfSenders() - - // Alice is also removed from the map of senders, since it has no transaction left - nTxs, nSenders := cache.evictHighNonceTransactions() - require.Equal(t, uint32(1), nTxs) - require.Equal(t, uint32(1), nSenders) - require.Equal(t, int64(0), cache.CountSenders()) -} - func TestEviction_EvictSendersWhileTooManyTxs(t *testing.T) { config := CacheConfig{ NumChunksHint: 16, @@ -141,11 +86,9 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfCount(t *testing.T) { cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 1000, 100000, 700*oneTrilion)) cache.doEviction() - require.Equal(t, uint32(0), cache.evictionJournal.passOneNumTxs) - require.Equal(t, uint32(0), cache.evictionJournal.passOneNumSenders) - require.Equal(t, uint32(2), cache.evictionJournal.passTwoNumTxs) - require.Equal(t, uint32(2), cache.evictionJournal.passTwoNumSenders) - require.Equal(t, uint32(1), cache.evictionJournal.passTwoNumSteps) + require.Equal(t, uint32(2), cache.evictionJournal.passOneNumTxs) + require.Equal(t, uint32(2), cache.evictionJournal.passOneNumSenders) + require.Equal(t, uint32(1), cache.evictionJournal.passOneNumSteps) // Alice and Bob evicted. Carol still there. _, ok := cache.GetByTxHash([]byte("hash-carol")) @@ -173,11 +116,9 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfSize(t *testing.T) { require.InDelta(t, float64(100), cache.getRawScoreOfSender("carol"), delta) cache.doEviction() - require.Equal(t, uint32(0), cache.evictionJournal.passOneNumTxs) - require.Equal(t, uint32(0), cache.evictionJournal.passOneNumSenders) - require.Equal(t, uint32(2), cache.evictionJournal.passTwoNumTxs) - require.Equal(t, uint32(2), cache.evictionJournal.passTwoNumSenders) - require.Equal(t, uint32(1), cache.evictionJournal.passTwoNumSteps) + require.Equal(t, uint32(2), cache.evictionJournal.passOneNumTxs) + require.Equal(t, uint32(2), cache.evictionJournal.passOneNumSenders) + require.Equal(t, uint32(1), cache.evictionJournal.passOneNumSteps) // Alice and Bob evicted (lower score). Carol still there. _, ok := cache.GetByTxHash([]byte("hash-carol")) @@ -252,8 +193,6 @@ func Test_AddWithEviction_UniformDistribution_25000x10(t *testing.T) { NumBytesThreshold: 1000000000, CountThreshold: 240000, NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, - LargeNumOfTxsForASender: 1000, - NumTxsToEvictFromASender: 250, } numSenders := 25000 diff --git a/storage/txcache/monitoring.go b/storage/txcache/monitoring.go index 5dcac6617d..95848b450c 100644 --- a/storage/txcache/monitoring.go +++ b/storage/txcache/monitoring.go @@ -93,14 +93,11 @@ type evictionJournal struct { evictionPerformed bool passOneNumTxs uint32 passOneNumSenders uint32 - passTwoNumTxs uint32 - passTwoNumSenders uint32 - passTwoNumSteps uint32 + passOneNumSteps uint32 } func (journal *evictionJournal) display() { - log.Debug("Eviction.pass1:", "txs", journal.passOneNumTxs, "senders", journal.passOneNumSenders) - log.Debug("Eviction.pass2:", "txs", journal.passTwoNumTxs, "senders", journal.passTwoNumSenders, "steps", journal.passTwoNumSteps) + log.Debug("Eviction.pass1:", "txs", journal.passOneNumTxs, "senders", journal.passOneNumSenders, "steps", journal.passOneNumSteps) } func (cache *TxCache) diagnose() { diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index cecef150a0..c163a54c18 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -246,8 +246,6 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumBytesThreshold: math.MaxUint32, CountThreshold: 100, NumSendersToEvictInOneStep: 1, - LargeNumOfTxsForASender: math.MaxUint32, - NumTxsToEvictFromASender: 0, } // 11 * 10 @@ -261,8 +259,6 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumBytesThreshold: math.MaxUint32, CountThreshold: 250000, NumSendersToEvictInOneStep: 1, - LargeNumOfTxsForASender: math.MaxUint32, - NumTxsToEvictFromASender: 0, } // 100 * 1000 diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index fbb5d16072..27bc512df6 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -114,31 +114,6 @@ func (listForSender *txListForSender) onRemovedListElement(element *list.Element listForSender.onScoreChange(listForSender) } -// RemoveHighNonceTxs removes "count" transactions from the back of the list -func (listForSender *txListForSender) RemoveHighNonceTxs(count uint32) [][]byte { - listForSender.mutex.Lock() - defer listForSender.mutex.Unlock() - - removedTxHashes := make([][]byte, count) - - index := uint32(0) - var previous *list.Element - for element := listForSender.items.Back(); element != nil && count > index; element = previous { - // Remove node - previous = element.Prev() - listForSender.items.Remove(element) - listForSender.onRemovedListElement(element) - - // Keep track of removed transaction - value := element.Value.(*WrappedTransaction) - removedTxHashes[index] = value.TxHash - - index++ - } - - return removedTxHashes -} - // This function should only be used in critical section (listForSender.mutex) func (listForSender *txListForSender) findListElementWithTx(txToFind *WrappedTransaction) *list.Element { for element := listForSender.items.Front(); element != nil; element = element.Next() { diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 144357e3f6..8632c034d0 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -97,37 +97,6 @@ func TestListForSender_RemoveTransaction_NoPanicWhenTxMissing(t *testing.T) { require.Equal(t, 0, list.items.Len()) } -func TestListForSender_RemoveHighNonceTransactions(t *testing.T) { - list := newListToTest() - - for index := 0; index < 100; index++ { - list.AddTx(createTx([]byte{byte(index)}, ".", uint64(index))) - } - - list.RemoveHighNonceTxs(50) - require.Equal(t, 50, list.items.Len()) - - list.RemoveHighNonceTxs(20) - require.Equal(t, 30, list.items.Len()) - - list.RemoveHighNonceTxs(30) - require.Equal(t, 0, list.items.Len()) -} - -func TestListForSender_RemoveHighNonceTransactions_NoPanicWhenCornerCases(t *testing.T) { - list := newListToTest() - - for index := 0; index < 100; index++ { - list.AddTx(createTx([]byte{byte(index)}, ".", uint64(index))) - } - - list.RemoveHighNonceTxs(0) - require.Equal(t, 100, list.items.Len()) - - list.RemoveHighNonceTxs(500) - require.Equal(t, 0, list.items.Len()) -} - func TestListForSender_SelectBatchTo(t *testing.T) { list := newListToTest() From 56aced516f04d6b80e324187bca520e6bbf36730 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Mon, 11 May 2020 14:10:58 +0300 Subject: [PATCH 03/79] add unit tests for trieStorageManager --- cmd/node/config/config.toml | 2 +- data/trie/pruningBuffer.go | 2 +- data/trie/trieStorageManager_test.go | 129 +++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 2 deletions(-) diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 03d308736e..1bfa8298da 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -187,7 +187,7 @@ MaxOpenFiles = 10 [TrieStorageManagerConfig] - PruningBufferLen = 1000 + PruningBufferLen = 100000 SnapshotsBufferLen = 1000000 MaxSnapshots = 2 diff --git a/data/trie/pruningBuffer.go b/data/trie/pruningBuffer.go index b4097073ca..61a8a685dd 100644 --- a/data/trie/pruningBuffer.go +++ b/data/trie/pruningBuffer.go @@ -22,7 +22,7 @@ func (pb *pruningBuffer) add(rootHash []byte) { defer pb.mutOp.Unlock() if uint32(len(pb.buffer)) == pb.size { - log.Trace("pruning buffer is full", "rootHash", rootHash) + log.Warn("pruning buffer is full", "rootHash", rootHash) return } diff --git a/data/trie/trieStorageManager_test.go b/data/trie/trieStorageManager_test.go index 3eb045de4b..c530119829 100644 --- a/data/trie/trieStorageManager_test.go +++ b/data/trie/trieStorageManager_test.go @@ -386,3 +386,132 @@ func TestTrieSnapshottingAndCheckpointConcurrently(t *testing.T) { assert.NotNil(t, val) assert.Nil(t, err) } + +func TestTriePruneAndCancelPruneWhileSnapshotInProgressAddsToPruningBuffer(t *testing.T) { + t.Parallel() + + tr, trieStorage, _ := newEmptyTrie() + _ = tr.Update([]byte("doe"), []byte("reindeer")) + _ = tr.Update([]byte("dog"), []byte("puppy")) + _ = tr.Update([]byte("dogglesworth"), []byte("cat")) + _ = tr.Commit() + oldRootHash, _ := tr.Root() + + _ = tr.Update([]byte("dogglesworth"), []byte("catnip")) + _ = tr.Commit() + newRootHash, _ := tr.Root() + + tr.EnterSnapshotMode() + tr.Prune(oldRootHash, data.OldRoot) + tr.CancelPrune(newRootHash, data.NewRoot) + tr.ExitSnapshotMode() + + assert.Equal(t, 2, trieStorage.pruningBuffer.len()) +} + +func TestTriePruneOnRollbackWhileSnapshotInProgressCancelsPrune(t *testing.T) { + t.Parallel() + + tr, trieStorage, _ := newEmptyTrie() + _ = tr.Update([]byte("doe"), []byte("reindeer")) + _ = tr.Update([]byte("dog"), []byte("puppy")) + _ = tr.Update([]byte("dogglesworth"), []byte("cat")) + _ = tr.Commit() + oldRootHash, _ := tr.Root() + + _ = tr.Update([]byte("dogglesworth"), []byte("catnip")) + _ = tr.Commit() + newRootHash, _ := tr.Root() + + tr.EnterSnapshotMode() + tr.CancelPrune(oldRootHash, data.OldRoot) + tr.Prune(newRootHash, data.NewRoot) + tr.ExitSnapshotMode() + + assert.Equal(t, 1, trieStorage.pruningBuffer.len()) +} + +func TestTriePruneAfterSnapshotIsDonePrunesBufferedHashes(t *testing.T) { + t.Parallel() + + tr, trieStorage, _ := newEmptyTrie() + _ = tr.Update([]byte("doe"), []byte("reindeer")) + _ = tr.Update([]byte("dog"), []byte("puppy")) + _ = tr.Update([]byte("dogglesworth"), []byte("cat")) + newHashes, _ := tr.GetDirtyHashes() + tr.SetNewHashes(newHashes) + _ = tr.Commit() + oldRootHash, _ := tr.Root() + + _ = tr.Update([]byte("dogglesworth"), []byte("catnip")) + newHashes, _ = tr.GetDirtyHashes() + tr.SetNewHashes(newHashes) + _ = tr.Commit() + newRootHash, _ := tr.Root() + + tr.EnterSnapshotMode() + tr.Prune(oldRootHash, data.OldRoot) + tr.CancelPrune(newRootHash, data.NewRoot) + tr.ExitSnapshotMode() + + tr.Prune(oldRootHash, data.NewRoot) + + assert.Equal(t, 0, trieStorage.pruningBuffer.len()) +} + +func TestTrieCancelPruneAndPruningBufferNotEmptyAddsToPruningBuffer(t *testing.T) { + t.Parallel() + + tr, trieStorage, _ := newEmptyTrie() + _ = tr.Update([]byte("doe"), []byte("reindeer")) + _ = tr.Update([]byte("dog"), []byte("puppy")) + _ = tr.Update([]byte("dogglesworth"), []byte("cat")) + _ = tr.Commit() + oldRootHash, _ := tr.Root() + + _ = tr.Update([]byte("dogglesworth"), []byte("catnip")) + _ = tr.Commit() + newRootHash, _ := tr.Root() + + tr.EnterSnapshotMode() + tr.Prune(oldRootHash, data.OldRoot) + tr.CancelPrune(newRootHash, data.NewRoot) + tr.ExitSnapshotMode() + + tr.CancelPrune(oldRootHash, data.NewRoot) + + assert.Equal(t, 3, trieStorage.pruningBuffer.len()) +} + +func TestTriePruneAndCancelPruneAddedToBufferInOrder(t *testing.T) { + t.Parallel() + + tr, trieStorage, _ := newEmptyTrie() + _ = tr.Update([]byte("doe"), []byte("reindeer")) + _ = tr.Update([]byte("dog"), []byte("puppy")) + _ = tr.Update([]byte("dogglesworth"), []byte("cat")) + _ = tr.Commit() + oldRootHash, _ := tr.Root() + + _ = tr.Update([]byte("dogglesworth"), []byte("catnip")) + _ = tr.Commit() + newRootHash, _ := tr.Root() + + tr.EnterSnapshotMode() + tr.Prune(oldRootHash, data.OldRoot) + tr.CancelPrune(newRootHash, data.NewRoot) + tr.ExitSnapshotMode() + + tr.CancelPrune(oldRootHash, data.NewRoot) + + bufferedHashes := trieStorage.pruningBuffer.removeAll() + + expectedHash := append(oldRootHash, byte(data.OldRoot)) + assert.Equal(t, append(expectedHash, byte(prune)), bufferedHashes[0]) + + expectedHash = append(newRootHash, byte(data.NewRoot)) + assert.Equal(t, append(expectedHash, byte(cancelPrune)), bufferedHashes[1]) + + expectedHash = append(oldRootHash, byte(data.NewRoot)) + assert.Equal(t, append(expectedHash, byte(cancelPrune)), bufferedHashes[2]) +} From a8642f2007183682515ad06604b735c6352cc3d1 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 14:33:47 +0300 Subject: [PATCH 04/79] Sketch config. --- cmd/node/config/config.toml | 2 ++ config/config.go | 10 +++--- dataRetriever/constants.go | 8 ----- .../factory/txpool/txPoolFactory_test.go | 2 +- dataRetriever/txpool/argShardedTxPool.go | 6 ++++ dataRetriever/txpool/shardedTxPool.go | 6 ++-- dataRetriever/txpool/shardedTxPool_test.go | 36 +++++++++++++------ storage/factory/common.go | 10 +++--- storage/storageUnit/storageunit.go | 12 ++++--- 9 files changed, 56 insertions(+), 36 deletions(-) diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 8c44267862..d331633389 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -220,7 +220,9 @@ [TxDataPool] Size = 900000 + SizePerSender = 1000 SizeInBytes = 524288000 + SizeInBytesPerSender = 614400 Type = "TxCache" Shards = 16 diff --git a/config/config.go b/config/config.go index 47713b6ac8..8fefa671ec 100644 --- a/config/config.go +++ b/config/config.go @@ -2,10 +2,12 @@ package config // CacheConfig will map the json cache configuration type CacheConfig struct { - Type string `json:"type"` - Size uint32 `json:"size"` - SizeInBytes uint32 `json:"sizeInBytes"` - Shards uint32 `json:"shards"` + Type string `json:"type"` + Size uint32 `json:"size"` + SizePerSender uint32 `json:"sizePerSender"` + SizeInBytes uint32 `json:"sizeInBytes"` + SizeInBytesPerSender uint32 `json:"sizeInBytesPerSender"` + Shards uint32 `json:"shards"` } //HeadersPoolConfig will map the headers cache configuration diff --git a/dataRetriever/constants.go b/dataRetriever/constants.go index a368851036..e171d666b7 100644 --- a/dataRetriever/constants.go +++ b/dataRetriever/constants.go @@ -3,13 +3,5 @@ package dataRetriever // TxPoolNumSendersToEvictInOneStep instructs tx pool eviction algorithm to remove this many senders when eviction takes place const TxPoolNumSendersToEvictInOneStep = uint32(100) -// TxPoolLargeNumOfTxsForASender instructs tx pool eviction algorithm to tag a sender with more transactions than this value -// as a "sender with a large number of transactions" -const TxPoolLargeNumOfTxsForASender = uint32(500) - -// TxPoolNumTxsToEvictFromASender instructs tx pool eviction algorithm to remove this many transactions -// for "a sender with a large number of transactions" when eviction takes place -const TxPoolNumTxsToEvictFromASender = uint32(100) - // TxPoolMinSizeInBytes is the lower limit of the tx cache / eviction parameter "sizeInBytes" const TxPoolMinSizeInBytes = uint32(40960) diff --git a/dataRetriever/factory/txpool/txPoolFactory_test.go b/dataRetriever/factory/txpool/txPoolFactory_test.go index 3c6c9745aa..5cd85f4c65 100644 --- a/dataRetriever/factory/txpool/txPoolFactory_test.go +++ b/dataRetriever/factory/txpool/txPoolFactory_test.go @@ -24,7 +24,7 @@ func Test_CreateNewTxPool_ShardedData(t *testing.T) { } func Test_CreateNewTxPool_ShardedTxPool(t *testing.T) { - config := storageUnit.CacheConfig{Size: 100, SizeInBytes: 40960, Shards: 1} + config := storageUnit.CacheConfig{Size: 100, SizePerSender: 1, SizeInBytes: 40960, SizeInBytesPerSender: 40960, Shards: 1} args := txpool.ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 1} txPool, err := CreateTxPool(args) diff --git a/dataRetriever/txpool/argShardedTxPool.go b/dataRetriever/txpool/argShardedTxPool.go index 362c6f47ce..204a5c754c 100644 --- a/dataRetriever/txpool/argShardedTxPool.go +++ b/dataRetriever/txpool/argShardedTxPool.go @@ -21,9 +21,15 @@ func (args *ArgShardedTxPool) verify() error { if config.SizeInBytes < dataRetriever.TxPoolMinSizeInBytes { return fmt.Errorf("%w: config.SizeInBytes is less than [dataRetriever.TxPoolMinSizeInBytes]", dataRetriever.ErrCacheConfigInvalidSizeInBytes) } + if config.SizeInBytesPerSender < dataRetriever.TxPoolMinSizeInBytes { + return fmt.Errorf("%w: config.SizeInBytesPerSender is less than [dataRetriever.TxPoolMinSizeInBytes]", dataRetriever.ErrCacheConfigInvalidSizeInBytes) + } if config.Size < 1 { return fmt.Errorf("%w: config.Size is less than 1", dataRetriever.ErrCacheConfigInvalidSize) } + if config.SizePerSender < 1 { + return fmt.Errorf("%w: config.SizePerSender is less than 1", dataRetriever.ErrCacheConfigInvalidSize) + } if config.Shards < 1 { return fmt.Errorf("%w: config.Shards (map chunks) is less than 1", dataRetriever.ErrCacheConfigInvalidShards) } diff --git a/dataRetriever/txpool/shardedTxPool.go b/dataRetriever/txpool/shardedTxPool.go index 18a7cd9c95..6c4bcfea46 100644 --- a/dataRetriever/txpool/shardedTxPool.go +++ b/dataRetriever/txpool/shardedTxPool.go @@ -4,7 +4,7 @@ import ( "strconv" "sync" - "github.com/ElrondNetwork/elrond-go-logger" + logger "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core/counting" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/dataRetriever" @@ -51,10 +51,10 @@ func NewShardedTxPool(args ArgShardedTxPool) (dataRetriever.ShardedDataCacherNot NumChunksHint: args.Config.Shards, EvictionEnabled: true, NumBytesThreshold: args.Config.SizeInBytes / numCaches, + NumBytesPerSenderThreshold: args.Config.SizeInBytesPerSender, CountThreshold: args.Config.Size / numCaches, + CountPerSenderThreshold: args.Config.SizePerSender, NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, - LargeNumOfTxsForASender: dataRetriever.TxPoolLargeNumOfTxsForASender, - NumTxsToEvictFromASender: dataRetriever.TxPoolNumTxsToEvictFromASender, MinGasPriceMicroErd: uint32(args.MinGasPrice / oneTrilion), } diff --git a/dataRetriever/txpool/shardedTxPool_test.go b/dataRetriever/txpool/shardedTxPool_test.go index a24de4aec6..7e1e91788d 100644 --- a/dataRetriever/txpool/shardedTxPool_test.go +++ b/dataRetriever/txpool/shardedTxPool_test.go @@ -24,29 +24,43 @@ func Test_NewShardedTxPool(t *testing.T) { } func Test_NewShardedTxPool_WhenBadConfig(t *testing.T) { - goodArgs := ArgShardedTxPool{Config: storageUnit.CacheConfig{Size: 100, SizeInBytes: 40960, Shards: 16}, MinGasPrice: 100000000000000, NumberOfShards: 1} + goodArgs := ArgShardedTxPool{Config: storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16}, MinGasPrice: 100000000000000, NumberOfShards: 1} args := goodArgs - args.Config = storageUnit.CacheConfig{SizeInBytes: 1} + args.Config.SizeInBytes = 1 pool, err := NewShardedTxPool(args) require.Nil(t, pool) require.NotNil(t, err) require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidSizeInBytes.Error()) args = goodArgs - args.Config = storageUnit.CacheConfig{SizeInBytes: 40960, Size: 1} + args.Config.SizeInBytesPerSender = 1 pool, err = NewShardedTxPool(args) require.Nil(t, pool) require.NotNil(t, err) - require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidShards.Error()) + require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidSizeInBytes.Error()) + + args = goodArgs + args.Config.Size = 0 + pool, err = NewShardedTxPool(args) + require.Nil(t, pool) + require.NotNil(t, err) + require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidSize.Error()) args = goodArgs - args.Config = storageUnit.CacheConfig{SizeInBytes: 40960, Shards: 1} + args.Config.SizePerSender = 0 pool, err = NewShardedTxPool(args) require.Nil(t, pool) require.NotNil(t, err) require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidSize.Error()) + args = goodArgs + args.Config.Shards = 0 + pool, err = NewShardedTxPool(args) + require.Nil(t, pool) + require.NotNil(t, err) + require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidShards.Error()) + args = goodArgs args.MinGasPrice = 0 pool, err = NewShardedTxPool(args) @@ -63,7 +77,7 @@ func Test_NewShardedTxPool_WhenBadConfig(t *testing.T) { } func Test_NewShardedTxPool_ComputesCacheConfig(t *testing.T) { - config := storageUnit.CacheConfig{SizeInBytes: 524288000, Size: 900000, Shards: 1} + config := storageUnit.CacheConfig{SizeInBytes: 524288000, SizeInBytesPerSender: 614400, Size: 900000, SizePerSender: 1000, Shards: 1} args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 5} poolAsInterface, err := NewShardedTxPool(args) @@ -73,10 +87,10 @@ func Test_NewShardedTxPool_ComputesCacheConfig(t *testing.T) { require.Equal(t, true, pool.cacheConfigPrototype.EvictionEnabled) require.Equal(t, uint32(58254222), pool.cacheConfigPrototype.NumBytesThreshold) + require.Equal(t, uint32(614400), pool.cacheConfigPrototype.NumBytesPerSenderThreshold) require.Equal(t, uint32(100000), pool.cacheConfigPrototype.CountThreshold) + require.Equal(t, uint32(1000), pool.cacheConfigPrototype.CountPerSenderThreshold) require.Equal(t, uint32(100), pool.cacheConfigPrototype.NumSendersToEvictInOneStep) - require.Equal(t, uint32(500), pool.cacheConfigPrototype.LargeNumOfTxsForASender) - require.Equal(t, uint32(100), pool.cacheConfigPrototype.NumTxsToEvictFromASender) require.Equal(t, uint32(100), pool.cacheConfigPrototype.MinGasPriceMicroErd) require.Equal(t, uint32(291271110), pool.cacheConfigPrototypeForSelfShard.NumBytesThreshold) require.Equal(t, uint32(500000), pool.cacheConfigPrototypeForSelfShard.CountThreshold) @@ -304,7 +318,7 @@ func Test_NotImplementedFunctions(t *testing.T) { } func Test_routeToCacheUnions(t *testing.T) { - config := storageUnit.CacheConfig{Size: 100, SizeInBytes: 40960, Shards: 16} + config := storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16} args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 4, SelfShardID: 42} poolAsInterface, _ := NewShardedTxPool(args) pool := poolAsInterface.(*shardedTxPool) @@ -319,7 +333,7 @@ func Test_routeToCacheUnions(t *testing.T) { } func Test_getCacheConfig(t *testing.T) { - config := storageUnit.CacheConfig{Size: 150, SizeInBytes: 61440, Shards: 16} + config := storageUnit.CacheConfig{Size: 150, SizePerSender: 1, SizeInBytes: 61440, SizeInBytesPerSender: 40960, Shards: 16} args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 8, SelfShardID: 4} poolAsInterface, _ := NewShardedTxPool(args) pool := poolAsInterface.(*shardedTxPool) @@ -353,7 +367,7 @@ type thisIsNotATransaction struct { } func newTxPoolToTest() (dataRetriever.ShardedDataCacherNotifier, error) { - config := storageUnit.CacheConfig{Size: 100, SizeInBytes: 40960, Shards: 16} + config := storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16} args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 4} return NewShardedTxPool(args) } diff --git a/storage/factory/common.go b/storage/factory/common.go index fec9d8da1c..d431acfc94 100644 --- a/storage/factory/common.go +++ b/storage/factory/common.go @@ -13,10 +13,12 @@ const allFiles = -1 // GetCacherFromConfig will return the cache config needed for storage unit from a config came from the toml file func GetCacherFromConfig(cfg config.CacheConfig) storageUnit.CacheConfig { return storageUnit.CacheConfig{ - Size: cfg.Size, - SizeInBytes: cfg.SizeInBytes, - Type: storageUnit.CacheType(cfg.Type), - Shards: cfg.Shards, + Size: cfg.Size, + SizePerSender: cfg.SizePerSender, + SizeInBytes: cfg.SizeInBytes, + SizeInBytesPerSender: cfg.SizeInBytesPerSender, + Type: storageUnit.CacheType(cfg.Type), + Shards: cfg.Shards, } } diff --git a/storage/storageUnit/storageunit.go b/storage/storageUnit/storageunit.go index cf2703cc96..eecce45a64 100644 --- a/storage/storageUnit/storageunit.go +++ b/storage/storageUnit/storageunit.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/ElrondNetwork/elrond-go-logger" + logger "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/hashing" @@ -67,10 +67,12 @@ type UnitConfig struct { // CacheConfig holds the configurable elements of a cache type CacheConfig struct { - Type CacheType - SizeInBytes uint32 - Size uint32 - Shards uint32 + Type CacheType + SizeInBytes uint32 + SizeInBytesPerSender uint32 + Size uint32 + SizePerSender uint32 + Shards uint32 } // DBConfig holds the configurable elements of a database From fb7f7c773139cdea2bcc0a590bf8eca4794704f5 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Mon, 11 May 2020 14:38:25 +0300 Subject: [PATCH 05/79] remove SignalEndOfProcessing() --- data/trie/interceptedNode.go | 8 ---- .../bootstrap/epochStartMetaBlockProcessor.go | 4 -- process/interceptors/multiDataInterceptor.go | 4 -- .../processor/hdrInterceptorProcessor.go | 4 -- .../miniblockInterceptorProcessor.go | 4 -- .../processor/trieNodeInterceptorProcessor.go | 17 --------- .../trieNodeInterceptorProcessor_test.go | 38 ------------------- .../processor/txInterceptorProcessor.go | 4 -- process/interface.go | 1 - process/mock/interceptorProcessorStub.go | 4 -- 10 files changed, 88 deletions(-) diff --git a/data/trie/interceptedNode.go b/data/trie/interceptedNode.go index f7223b2373..afa42175fa 100644 --- a/data/trie/interceptedNode.go +++ b/data/trie/interceptedNode.go @@ -129,11 +129,3 @@ func (inTn *InterceptedTrieNode) Fee() *big.Int { func (inTn *InterceptedTrieNode) Identifiers() [][]byte { return [][]byte{inTn.hash} } - -// CreateEndOfProcessingTriggerNode changes the hash of the current node by appending the hash to the current hash. -// This construction will be used to trigger the end of processing for all of the received data -func (inTn *InterceptedTrieNode) CreateEndOfProcessingTriggerNode() { - inTn.mutex.Lock() - inTn.hash = append(inTn.hash, inTn.hash...) - inTn.mutex.Unlock() -} diff --git a/epochStart/bootstrap/epochStartMetaBlockProcessor.go b/epochStart/bootstrap/epochStartMetaBlockProcessor.go index d0f97b24bb..ecc873a9ca 100644 --- a/epochStart/bootstrap/epochStartMetaBlockProcessor.go +++ b/epochStart/bootstrap/epochStartMetaBlockProcessor.go @@ -251,10 +251,6 @@ func (e *epochStartMetaBlockProcessor) processEntry( return false } -// SignalEndOfProcessing won't do anything -func (e *epochStartMetaBlockProcessor) SignalEndOfProcessing(_ []process.InterceptedData) { -} - // IsInterfaceNil returns true if there is no value under the interface func (e *epochStartMetaBlockProcessor) IsInterfaceNil() bool { return e == nil diff --git a/process/interceptors/multiDataInterceptor.go b/process/interceptors/multiDataInterceptor.go index 6a60b3456f..c2a47649c9 100644 --- a/process/interceptors/multiDataInterceptor.go +++ b/process/interceptors/multiDataInterceptor.go @@ -99,14 +99,12 @@ func (mdi *MultiDataInterceptor) ProcessReceivedMessage(message p2p.MessageP2P, return err } - interceptedMultiData := make([]process.InterceptedData, 0) lastErrEncountered := error(nil) wgProcess := &sync.WaitGroup{} wgProcess.Add(len(multiDataBuff)) go func() { wgProcess.Wait() - mdi.processor.SignalEndOfProcessing(interceptedMultiData) mdi.throttler.EndProcessing() }() @@ -119,8 +117,6 @@ func (mdi *MultiDataInterceptor) ProcessReceivedMessage(message p2p.MessageP2P, continue } - interceptedMultiData = append(interceptedMultiData, interceptedData) - isForCurrentShard := interceptedData.IsForCurrentShard() isWhiteListed := mdi.whiteListRequest.IsWhiteListed(interceptedData) shouldProcess := isForCurrentShard || isWhiteListed diff --git a/process/interceptors/processor/hdrInterceptorProcessor.go b/process/interceptors/processor/hdrInterceptorProcessor.go index db52f9e28a..d0184e5a56 100644 --- a/process/interceptors/processor/hdrInterceptorProcessor.go +++ b/process/interceptors/processor/hdrInterceptorProcessor.go @@ -68,10 +68,6 @@ func (hip *HdrInterceptorProcessor) Save(data process.InterceptedData, _ p2p.Pee return nil } -// SignalEndOfProcessing signals the end of processing -func (hip *HdrInterceptorProcessor) SignalEndOfProcessing(data []process.InterceptedData) { -} - // IsInterfaceNil returns true if there is no value under the interface func (hip *HdrInterceptorProcessor) IsInterfaceNil() bool { return hip == nil diff --git a/process/interceptors/processor/miniblockInterceptorProcessor.go b/process/interceptors/processor/miniblockInterceptorProcessor.go index 4e03533ee5..a2b0b69f74 100644 --- a/process/interceptors/processor/miniblockInterceptorProcessor.go +++ b/process/interceptors/processor/miniblockInterceptorProcessor.go @@ -100,10 +100,6 @@ func (mip *MiniblockInterceptorProcessor) isMbCrossShard(miniblock *block.MiniBl return miniblock.SenderShardID != mip.shardCoordinator.SelfId() } -// SignalEndOfProcessing signals the end of processing -func (mip *MiniblockInterceptorProcessor) SignalEndOfProcessing(_ []process.InterceptedData) { -} - // IsInterfaceNil returns true if there is no value under the interface func (mip *MiniblockInterceptorProcessor) IsInterfaceNil() bool { return mip == nil diff --git a/process/interceptors/processor/trieNodeInterceptorProcessor.go b/process/interceptors/processor/trieNodeInterceptorProcessor.go index f90ccee478..51aac28b67 100644 --- a/process/interceptors/processor/trieNodeInterceptorProcessor.go +++ b/process/interceptors/processor/trieNodeInterceptorProcessor.go @@ -42,23 +42,6 @@ func (tnip *TrieNodeInterceptorProcessor) Save(data process.InterceptedData, _ p return nil } -// SignalEndOfProcessing signals the end of processing -func (tnip *TrieNodeInterceptorProcessor) SignalEndOfProcessing(data []process.InterceptedData) { - nodeData, ok := data[0].(*trie.InterceptedTrieNode) - if !ok { - log.Debug("intercepted data is not a trie node") - return - } - - // TODO instead of using a node to trigger the end of processing, use a dedicated channel - // between interceptor and sync - nodeData.CreateEndOfProcessingTriggerNode() - err := tnip.Save(nodeData, "") - if err != nil { - log.Debug(err.Error()) - } -} - // IsInterfaceNil returns true if there is no value under the interface func (tnip *TrieNodeInterceptorProcessor) IsInterfaceNil() bool { return tnip == nil diff --git a/process/interceptors/processor/trieNodeInterceptorProcessor_test.go b/process/interceptors/processor/trieNodeInterceptorProcessor_test.go index 38751e6fd9..8398fbf201 100644 --- a/process/interceptors/processor/trieNodeInterceptorProcessor_test.go +++ b/process/interceptors/processor/trieNodeInterceptorProcessor_test.go @@ -6,7 +6,6 @@ import ( "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data/trie" "github.com/ElrondNetwork/elrond-go/process" - "github.com/ElrondNetwork/elrond-go/process/block/interceptedBlocks" "github.com/ElrondNetwork/elrond-go/process/interceptors/processor" "github.com/ElrondNetwork/elrond-go/process/mock" "github.com/stretchr/testify/assert" @@ -66,43 +65,6 @@ func TestTrieNodesInterceptorProcessor_SaveShouldPutInCacher(t *testing.T) { assert.True(t, putCalled) } -func TestTrieNodeInterceptorProcessor_SignalEndOfProcessingWrongTypeShouldNotPutInCache(t *testing.T) { - t.Parallel() - - cacheMock := &mock.CacherStub{ - PutCalled: func(key []byte, value interface{}) bool { - assert.Fail(t, "should have not arrived here") - return false - }, - } - tnip, _ := processor.NewTrieNodesInterceptorProcessor(cacheMock) - - intData := interceptedBlocks.InterceptedHeader{} - slc := make([]process.InterceptedData, 0) - slc = append(slc, &intData) - tnip.SignalEndOfProcessing(slc) -} - -func TestTrieNodeInterceptorProcessor_SignalEndOfProcessingShouldWork(t *testing.T) { - t.Parallel() - - putWasCalled := false - cacheMock := &mock.CacherStub{ - PutCalled: func(key []byte, value interface{}) bool { - putWasCalled = true - return true - }, - } - tnip, _ := processor.NewTrieNodesInterceptorProcessor(cacheMock) - - intData := trie.InterceptedTrieNode{} - slc := make([]process.InterceptedData, 0) - slc = append(slc, &intData) - tnip.SignalEndOfProcessing(slc) - - assert.True(t, putWasCalled) -} - //------- IsInterfaceNil func TestTrieNodesInterceptorProcessor_IsInterfaceNil(t *testing.T) { diff --git a/process/interceptors/processor/txInterceptorProcessor.go b/process/interceptors/processor/txInterceptorProcessor.go index 98e26d6ad6..29431093cd 100644 --- a/process/interceptors/processor/txInterceptorProcessor.go +++ b/process/interceptors/processor/txInterceptorProcessor.go @@ -60,10 +60,6 @@ func (txip *TxInterceptorProcessor) Save(data process.InterceptedData, _ p2p.Pee return nil } -// SignalEndOfProcessing signals the end of processing -func (txip *TxInterceptorProcessor) SignalEndOfProcessing(_ []process.InterceptedData) { -} - // IsInterfaceNil returns true if there is no value under the interface func (txip *TxInterceptorProcessor) IsInterfaceNil() bool { return txip == nil diff --git a/process/interface.go b/process/interface.go index 0d6d476bc9..67a1ca0f4b 100644 --- a/process/interface.go +++ b/process/interface.go @@ -97,7 +97,6 @@ type InterceptedData interface { type InterceptorProcessor interface { Validate(data InterceptedData, fromConnectedPeer p2p.PeerID) error Save(data InterceptedData, fromConnectedPeer p2p.PeerID) error - SignalEndOfProcessing(data []InterceptedData) IsInterfaceNil() bool } diff --git a/process/mock/interceptorProcessorStub.go b/process/mock/interceptorProcessorStub.go index 0ccbff7bef..72b3deec90 100644 --- a/process/mock/interceptorProcessorStub.go +++ b/process/mock/interceptorProcessorStub.go @@ -21,10 +21,6 @@ func (ips *InterceptorProcessorStub) Save(data process.InterceptedData, _ p2p.Pe return ips.SaveCalled(data) } -// SignalEndOfProcessing - -func (ips *InterceptorProcessorStub) SignalEndOfProcessing(_ []process.InterceptedData) { -} - // IsInterfaceNil - func (ips *InterceptorProcessorStub) IsInterfaceNil() bool { return ips == nil From 879add50e7e6914e62af48b6eff400c187bbcd3e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 14:54:53 +0300 Subject: [PATCH 06/79] Fix initialization of mocks etc. --- epochStart/metachain/epochStartData_test.go | 8 +++++--- integrationTests/consensus/testInitializer.go | 8 +++++--- integrationTests/testInitializer.go | 8 +++++--- process/block/preprocess/transactions_test.go | 8 +++++--- process/block/shardblock_test.go | 8 +++++--- process/coordinator/process_test.go | 8 +++++--- process/mock/poolsHolderMock.go | 8 +++++--- update/mock/poolsHolderMock.go | 8 +++++--- 8 files changed, 40 insertions(+), 24 deletions(-) diff --git a/epochStart/metachain/epochStartData_test.go b/epochStart/metachain/epochStartData_test.go index d9b1ca3a91..5563c0fdaa 100644 --- a/epochStart/metachain/epochStartData_test.go +++ b/epochStart/metachain/epochStartData_test.go @@ -102,9 +102,11 @@ func createTxPool(selfShardID uint32) (dataRetriever.ShardedDataCacherNotifier, return txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 16, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/integrationTests/consensus/testInitializer.go b/integrationTests/consensus/testInitializer.go index e291c4c1b8..e1249e03c5 100644 --- a/integrationTests/consensus/testInitializer.go +++ b/integrationTests/consensus/testInitializer.go @@ -164,9 +164,11 @@ func createTestShardDataPool() dataRetriever.PoolsHolder { txPool, _ := txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 1, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index 46b19daf11..d5f57e50d5 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -1901,9 +1901,11 @@ func createTxPool(selfShardID uint32) (dataRetriever.ShardedDataCacherNotifier, return txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 16, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/process/block/preprocess/transactions_test.go b/process/block/preprocess/transactions_test.go index f6c46390ed..676bde4d61 100644 --- a/process/block/preprocess/transactions_test.go +++ b/process/block/preprocess/transactions_test.go @@ -1057,9 +1057,11 @@ func createTxPool() (dataRetriever.ShardedDataCacherNotifier, error) { return txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 1, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/process/block/shardblock_test.go b/process/block/shardblock_test.go index 42c5be6feb..2f2528804a 100644 --- a/process/block/shardblock_test.go +++ b/process/block/shardblock_test.go @@ -49,9 +49,11 @@ func createTestShardDataPool() dataRetriever.PoolsHolder { txPool, _ := txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 1, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/process/coordinator/process_test.go b/process/coordinator/process_test.go index eadcf6ce54..87fd193fb1 100644 --- a/process/coordinator/process_test.go +++ b/process/coordinator/process_test.go @@ -2548,9 +2548,11 @@ func createTxPool() (dataRetriever.ShardedDataCacherNotifier, error) { return txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 100000, - SizeInBytes: 1000000000, - Shards: 1, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/process/mock/poolsHolderMock.go b/process/mock/poolsHolderMock.go index 89f8ac9b3b..9bd448e8c1 100644 --- a/process/mock/poolsHolderMock.go +++ b/process/mock/poolsHolderMock.go @@ -30,9 +30,11 @@ func NewPoolsHolderMock() *PoolsHolderMock { phf.transactions, _ = txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 10000, - SizeInBytes: 1000000000, - Shards: 16, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, diff --git a/update/mock/poolsHolderMock.go b/update/mock/poolsHolderMock.go index 54e593f924..9d2680b65c 100644 --- a/update/mock/poolsHolderMock.go +++ b/update/mock/poolsHolderMock.go @@ -29,9 +29,11 @@ func NewPoolsHolderMock() *PoolsHolderMock { phf.transactions, _ = txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 10000, - SizeInBytes: 1000000000, - Shards: 16, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, From 65b3c129653f1ecde6de3c7d4ade105effc963d9 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 16:55:37 +0300 Subject: [PATCH 07/79] Sketch application of limits. --- storage/txcache/txListForSender.go | 37 ++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 27bc512df6..5dfb691402 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -45,7 +45,7 @@ func newTxListForSender(sender string, cacheConfig *CacheConfig, onScoreChange s // AddTx adds a transaction in sender's list // This is a "sorted" insert -func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) { +func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) [][]byte { // We don't allow concurrent interceptor goroutines to mutate a given sender's list listForSender.mutex.Lock() defer listForSender.mutex.Unlock() @@ -61,12 +61,45 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) { } listForSender.onAddedTransaction(tx) + evicted := listForSender.applyLimit() + listForSender.triggerScoreChange() + + return evicted +} + +// This function should only be used in critical section (listForSender.mutex) +func (listForSender *txListForSender) applyLimit() [][]byte { + evictedTxHashes := make([][]byte, 0) + + for element := listForSender.items.Back(); element != nil; element = element.Prev() { + if !listForSender.isLimitReached() { + break + } + + listForSender.items.Remove(element) + listForSender.onRemovedListElement(element) + + // Keep track of removed transaction + value := element.Value.(*WrappedTransaction) + evictedTxHashes = append(evictedTxHashes, value.TxHash) + } + + return evictedTxHashes +} + +func (listForSender *txListForSender) isLimitReached() { + tooManyBytes := listForSender.totalBytes.Get() > listForSender.cacheConfig.NumBytesPerSenderThreshold + tooManyTxs := listForSender.countTx() > listForSender.cacheConfig.CountPerSenderThreshold + return tooManyBytes || tooManyTxs } func (listForSender *txListForSender) onAddedTransaction(tx *WrappedTransaction) { listForSender.totalBytes.Add(int64(estimateTxSize(tx))) listForSender.totalGas.Add(int64(estimateTxGas(tx))) listForSender.totalFee.Add(int64(estimateTxFee(tx))) +} + +func (listForSender *txListForSender) triggerScoreChange() { listForSender.onScoreChange(listForSender) } @@ -100,6 +133,7 @@ func (listForSender *txListForSender) RemoveTx(tx *WrappedTransaction) bool { if isFound { listForSender.items.Remove(marker) listForSender.onRemovedListElement(marker) + listForSender.triggerScoreChange() } return isFound @@ -111,7 +145,6 @@ func (listForSender *txListForSender) onRemovedListElement(element *list.Element listForSender.totalBytes.Subtract(int64(estimateTxSize(value))) listForSender.totalGas.Subtract(int64(estimateTxGas(value))) listForSender.totalFee.Subtract(int64(estimateTxFee(value))) - listForSender.onScoreChange(listForSender) } // This function should only be used in critical section (listForSender.mutex) From b0b1d0c8ddfca02a79d3bb6a28f51fe8de870ede Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 16:58:39 +0300 Subject: [PATCH 08/79] Fix build. --- storage/txcache/txListForSender.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 5dfb691402..6b71f9bb87 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -87,9 +87,9 @@ func (listForSender *txListForSender) applyLimit() [][]byte { return evictedTxHashes } -func (listForSender *txListForSender) isLimitReached() { - tooManyBytes := listForSender.totalBytes.Get() > listForSender.cacheConfig.NumBytesPerSenderThreshold - tooManyTxs := listForSender.countTx() > listForSender.cacheConfig.CountPerSenderThreshold +func (listForSender *txListForSender) isLimitReached() bool { + tooManyBytes := listForSender.totalBytes.Get() > int64(listForSender.cacheConfig.NumBytesPerSenderThreshold) + tooManyTxs := listForSender.countTx() > uint64(listForSender.cacheConfig.CountPerSenderThreshold) return tooManyBytes || tooManyTxs } From ae53ec5cc18bde3d57a4f041d316cdeac3594840 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 17:05:34 +0300 Subject: [PATCH 09/79] Temporarily bypass application of limits. --- storage/txcache/txListForSender.go | 7 +++++-- storage/txcache/txListForSender_test.go | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 6b71f9bb87..bcbf18fbfe 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -88,8 +88,11 @@ func (listForSender *txListForSender) applyLimit() [][]byte { } func (listForSender *txListForSender) isLimitReached() bool { - tooManyBytes := listForSender.totalBytes.Get() > int64(listForSender.cacheConfig.NumBytesPerSenderThreshold) - tooManyTxs := listForSender.countTx() > uint64(listForSender.cacheConfig.CountPerSenderThreshold) + maxBytes := int64(listForSender.cacheConfig.NumBytesPerSenderThreshold) + maxNumTxs := uint64(listForSender.cacheConfig.CountPerSenderThreshold) + tooManyBytes := maxBytes > 0 && listForSender.totalBytes.Get() > maxBytes + tooManyTxs := maxNumTxs > 0 && listForSender.countTx() > maxNumTxs + return tooManyBytes || tooManyTxs } diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 8632c034d0..61ec88bfc2 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -63,6 +63,10 @@ func TestListForSender_findTx(t *testing.T) { elementWithB := list.findListElementWithTx(txB) noElementWithD := list.findListElementWithTx(txD) + require.NotNil(t, elementWithA) + require.NotNil(t, elementWithANewer) + require.NotNil(t, elementWithB) + require.Equal(t, txA, elementWithA.Value.(*WrappedTransaction)) require.Equal(t, txANewer, elementWithANewer.Value.(*WrappedTransaction)) require.Equal(t, txB, elementWithB.Value.(*WrappedTransaction)) From dfdc4c4b7b35339f0604c40e3b9ea44a5cfa3c27 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 17:08:54 +0300 Subject: [PATCH 10/79] Add type alias. --- storage/txcache/eviction.go | 4 ++-- storage/txcache/txByHashMap.go | 6 +++--- storage/txcache/txCache.go | 4 +++- storage/txcache/txListForSender.go | 10 +++++----- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/storage/txcache/eviction.go b/storage/txcache/eviction.go index cf7e861435..64394de215 100644 --- a/storage/txcache/eviction.go +++ b/storage/txcache/eviction.go @@ -72,7 +72,7 @@ func (cache *TxCache) shouldContinueEvictingSenders() bool { } // This is called concurrently by two goroutines: the eviction one and the sweeping one -func (cache *TxCache) doEvictItems(txsToEvict [][]byte, sendersToEvict []string) (countTxs uint32, countSenders uint32) { +func (cache *TxCache) doEvictItems(txsToEvict txHashes, sendersToEvict []string) (countTxs uint32, countSenders uint32) { countTxs = cache.txByHash.RemoveTxsBulk(txsToEvict) countSenders = cache.txListBySender.RemoveSendersBulk(sendersToEvict) return @@ -116,7 +116,7 @@ func (cache *TxCache) evictSendersWhile(shouldContinue func() bool) (step uint32 // This is called concurrently by two goroutines: the eviction one and the sweeping one func (cache *TxCache) evictSendersAndTheirTxs(listsToEvict []*txListForSender) (uint32, uint32) { sendersToEvict := make([]string, 0, len(listsToEvict)) - txsToEvict := make([][]byte, 0, approximatelyCountTxInLists(listsToEvict)) + txsToEvict := make(txHashes, 0, approximatelyCountTxInLists(listsToEvict)) for _, txList := range listsToEvict { sendersToEvict = append(sendersToEvict, txList.sender) diff --git a/storage/txcache/txByHashMap.go b/storage/txcache/txByHashMap.go index 626bce1b8a..bf0c23ace6 100644 --- a/storage/txcache/txByHashMap.go +++ b/storage/txcache/txByHashMap.go @@ -57,7 +57,7 @@ func (txMap *txByHashMap) getTx(txHash string) (*WrappedTransaction, bool) { } // RemoveTxsBulk removes transactions, in bulk -func (txMap *txByHashMap) RemoveTxsBulk(txHashes [][]byte) uint32 { +func (txMap *txByHashMap) RemoveTxsBulk(txHashes txHashes) uint32 { oldCount := uint32(txMap.counter.Get()) for _, txHash := range txHashes { @@ -85,9 +85,9 @@ func (txMap *txByHashMap) clear() { txMap.counter.Set(0) } -func (txMap *txByHashMap) keys() [][]byte { +func (txMap *txByHashMap) keys() txHashes { keys := txMap.backingMap.Keys() - keysAsBytes := make([][]byte, len(keys)) + keysAsBytes := make(txHashes, len(keys)) for i := 0; i < len(keys); i++ { keysAsBytes[i] = []byte(keys[i]) } diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index 680c76ea6d..70a3e4cb46 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -10,6 +10,8 @@ import ( var _ storage.Cacher = (*TxCache)(nil) +type txHashes = [][]byte + // TxCache represents a cache-like structure (it has a fixed capacity and implements an eviction mechanism) for holding transactions type TxCache struct { name string @@ -234,7 +236,7 @@ func (cache *TxCache) RemoveOldest() { } // Keys returns the tx hashes in the cache -func (cache *TxCache) Keys() [][]byte { +func (cache *TxCache) Keys() txHashes { return cache.txByHash.keys() } diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index bcbf18fbfe..b7491ce567 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -45,7 +45,7 @@ func newTxListForSender(sender string, cacheConfig *CacheConfig, onScoreChange s // AddTx adds a transaction in sender's list // This is a "sorted" insert -func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) [][]byte { +func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) txHashes { // We don't allow concurrent interceptor goroutines to mutate a given sender's list listForSender.mutex.Lock() defer listForSender.mutex.Unlock() @@ -68,8 +68,8 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) [][]byte { } // This function should only be used in critical section (listForSender.mutex) -func (listForSender *txListForSender) applyLimit() [][]byte { - evictedTxHashes := make([][]byte, 0) +func (listForSender *txListForSender) applyLimit() txHashes { + evictedTxHashes := make(txHashes, 0) for element := listForSender.items.Back(); element != nil; element = element.Prev() { if !listForSender.isLimitReached() { @@ -236,11 +236,11 @@ func (listForSender *txListForSender) selectBatchTo(isFirstBatch bool, destinati } // getTxHashes returns the hashes of transactions in the list -func (listForSender *txListForSender) getTxHashes() [][]byte { +func (listForSender *txListForSender) getTxHashes() txHashes { listForSender.mutex.RLock() defer listForSender.mutex.RUnlock() - result := make([][]byte, 0, listForSender.countTx()) + result := make(txHashes, 0, listForSender.countTx()) for element := listForSender.items.Front(); element != nil; element = element.Next() { value := element.Value.(*WrappedTransaction) From 264c1eeb4217e049b3da5b0f70e1a459f649aa2e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 18:12:07 +0300 Subject: [PATCH 11/79] Sketch deduplication. --- storage/txcache/txCache.go | 6 ++++-- storage/txcache/txListBySenderMap.go | 4 ++-- storage/txcache/txListForSender.go | 10 ++++++++-- storage/txcache/wrappedTransaction.go | 10 +++++++++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index 70a3e4cb46..29f600776b 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -64,12 +64,14 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { } ok = true - added = cache.txByHash.addTx(tx) + added, evicted := cache.txListBySender.addTx(tx) if added { - cache.txListBySender.addTx(tx) + cache.txByHash.addTx(tx) cache.monitorTxAddition() } + cache.txByHash.RemoveTxsBulk(evicted) + return } diff --git a/storage/txcache/txListBySenderMap.go b/storage/txcache/txListBySenderMap.go index 5c41ad5e2a..119d4e755b 100644 --- a/storage/txcache/txListBySenderMap.go +++ b/storage/txcache/txListBySenderMap.go @@ -25,10 +25,10 @@ func newTxListBySenderMap(nChunksHint uint32, cacheConfig CacheConfig) txListByS } // addTx adds a transaction in the map, in the corresponding list (selected by its sender) -func (txMap *txListBySenderMap) addTx(tx *WrappedTransaction) { +func (txMap *txListBySenderMap) addTx(tx *WrappedTransaction) (bool, txHashes) { sender := string(tx.Tx.GetSndAddr()) listForSender := txMap.getOrAddListForSender(sender) - listForSender.AddTx(tx) + return listForSender.AddTx(tx) } func (txMap *txListBySenderMap) getOrAddListForSender(sender string) *txListForSender { diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index b7491ce567..6f8e13f865 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -45,7 +45,7 @@ func newTxListForSender(sender string, cacheConfig *CacheConfig, onScoreChange s // AddTx adds a transaction in sender's list // This is a "sorted" insert -func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) txHashes { +func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) (bool, txHashes) { // We don't allow concurrent interceptor goroutines to mutate a given sender's list listForSender.mutex.Lock() defer listForSender.mutex.Unlock() @@ -56,7 +56,13 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) txHashes { if insertionPlace == nil { listForSender.items.PushFront(tx) + // TODO: fix, check duplicated here. } else { + duplicated := insertionPlace.Value.(*WrappedTransaction).sameAs(tx) + if duplicated { + return false, nil + } + listForSender.items.InsertAfter(tx, insertionPlace) } @@ -64,7 +70,7 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) txHashes { evicted := listForSender.applyLimit() listForSender.triggerScoreChange() - return evicted + return true, evicted } // This function should only be used in critical section (listForSender.mutex) diff --git a/storage/txcache/wrappedTransaction.go b/storage/txcache/wrappedTransaction.go index 84c08b5afb..354fb058b6 100644 --- a/storage/txcache/wrappedTransaction.go +++ b/storage/txcache/wrappedTransaction.go @@ -1,6 +1,10 @@ package txcache -import "github.com/ElrondNetwork/elrond-go/data" +import ( + "bytes" + + "github.com/ElrondNetwork/elrond-go/data" +) // WrappedTransaction contains a transaction, its hash and extra information type WrappedTransaction struct { @@ -9,3 +13,7 @@ type WrappedTransaction struct { SenderShardID uint32 ReceiverShardID uint32 } + +func (wrappedTx *WrappedTransaction) sameAs(another *WrappedTransaction) bool { + return bytes.Equal(wrappedTx.TxHash, another.TxHash) +} From edef44f4b1774a1b5b5bf6ea3fd51d51643b64a5 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 18:33:56 +0300 Subject: [PATCH 12/79] Fix deduplication logic. --- storage/txcache/errors.go | 8 +++--- storage/txcache/txByHashMap.go | 1 + storage/txcache/txCache.go | 5 ++-- storage/txcache/txCache_test.go | 4 +-- storage/txcache/txListForSender.go | 39 ++++++++++++++++++------------ 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/storage/txcache/errors.go b/storage/txcache/errors.go index 26e9c62aad..ba52ba431b 100644 --- a/storage/txcache/errors.go +++ b/storage/txcache/errors.go @@ -2,8 +2,6 @@ package txcache import "fmt" -// ErrTxNotFound signals that the transactions was not found in the cache -var ErrTxNotFound = fmt.Errorf("tx not found in cache") - -// ErrMapsSyncInconsistency signals that there's an inconsistency between the internal maps on which the cache relies -var ErrMapsSyncInconsistency = fmt.Errorf("maps sync inconsistency between 'txByHash' and 'txListBySender'") +var errTxNotFound = fmt.Errorf("tx not found in cache") +var errMapsSyncInconsistency = fmt.Errorf("maps sync inconsistency between 'txByHash' and 'txListBySender'") +var errTxDuplicated = fmt.Errorf("duplicated tx") diff --git a/storage/txcache/txByHashMap.go b/storage/txcache/txByHashMap.go index bf0c23ace6..28372087d8 100644 --- a/storage/txcache/txByHashMap.go +++ b/storage/txcache/txByHashMap.go @@ -65,6 +65,7 @@ func (txMap *txByHashMap) RemoveTxsBulk(txHashes txHashes) uint32 { } newCount := uint32(txMap.counter.Get()) + // TODO: Check this for overflow as well? numRemoved := oldCount - newCount return numRemoved } diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index 29f600776b..b05cdc490e 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -71,7 +71,6 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { } cache.txByHash.RemoveTxsBulk(evicted) - return } @@ -146,7 +145,7 @@ func (cache *TxCache) doAfterSelection() { func (cache *TxCache) RemoveTxByHash(txHash []byte) error { tx, ok := cache.txByHash.removeTx(string(txHash)) if !ok { - return ErrTxNotFound + return errTxNotFound } cache.monitorTxRemoval() @@ -154,7 +153,7 @@ func (cache *TxCache) RemoveTxByHash(txHash []byte) error { found := cache.txListBySender.removeTx(tx) if !found { cache.onRemoveTxInconsistency(txHash) - return ErrMapsSyncInconsistency + return errMapsSyncInconsistency } return nil diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index c163a54c18..f5684808a9 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -107,7 +107,7 @@ func Test_GetByTxHash_And_Peek_And_Get(t *testing.T) { func Test_RemoveByTxHash_Error_WhenMissing(t *testing.T) { cache := newCacheToTest() err := cache.RemoveTxByHash([]byte("missing")) - require.Equal(t, err, ErrTxNotFound) + require.Equal(t, err, errTxNotFound) } func Test_RemoveByTxHash_Error_WhenMapsInconsistency(t *testing.T) { @@ -121,7 +121,7 @@ func Test_RemoveByTxHash_Error_WhenMapsInconsistency(t *testing.T) { cache.txListBySender.removeTx(tx) err := cache.RemoveTxByHash(txHash) - require.Equal(t, err, ErrMapsSyncInconsistency) + require.Equal(t, err, errMapsSyncInconsistency) } func Test_Clear(t *testing.T) { diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 6f8e13f865..a111609dbb 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -50,19 +50,14 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) (bool, txHas listForSender.mutex.Lock() defer listForSender.mutex.Unlock() - nonce := tx.Tx.GetNonce() - gasPrice := tx.Tx.GetGasPrice() - insertionPlace := listForSender.findInsertionPlace(nonce, gasPrice) + insertionPlace, err := listForSender.findInsertionPlace(tx) + if err != nil { + return false, nil + } if insertionPlace == nil { listForSender.items.PushFront(tx) - // TODO: fix, check duplicated here. } else { - duplicated := insertionPlace.Value.(*WrappedTransaction).sameAs(tx) - if duplicated { - return false, nil - } - listForSender.items.InsertAfter(tx, insertionPlace) } @@ -113,22 +108,34 @@ func (listForSender *txListForSender) triggerScoreChange() { } // This function should only be used in critical section (listForSender.mutex) -func (listForSender *txListForSender) findInsertionPlace(incomingNonce uint64, incomingGasPrice uint64) *list.Element { +func (listForSender *txListForSender) findInsertionPlace(incomingTx *WrappedTransaction) (*list.Element, error) { + incomingNonce := incomingTx.Tx.GetNonce() + incomingGasPrice := incomingTx.Tx.GetGasPrice() + for element := listForSender.items.Back(); element != nil; element = element.Prev() { - tx := element.Value.(*WrappedTransaction).Tx - nonce := tx.GetNonce() - gasPrice := tx.GetGasPrice() + tx := element.Value.(*WrappedTransaction) + nonce := tx.Tx.GetNonce() + gasPrice := tx.Tx.GetGasPrice() + + if incomingTx.sameAs(tx) { + // The incoming transaction will be discarded + return nil, errTxDuplicated + } if nonce == incomingNonce && gasPrice > incomingGasPrice { - return element + // The incoming transaction will be placed right after the existing one (with higher price). + return element, nil } if nonce < incomingNonce { - return element + // We've found the first transaction with a lower nonce than the incoming one, + // thus the incoming transaction will be placed right after this one. + return element, nil } } - return nil + // The incoming transaction will be inserted at the head of the list. + return nil, nil } // RemoveTx removes a transaction from the sender's list From a2efbd588bd8de5f766a303ab6a0b0a1dbf8000c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 18:52:27 +0300 Subject: [PATCH 13/79] Fix some tests, remove unused code. --- storage/txcache/testutils_test.go | 6 +++++- storage/txcache/txListBySenderMap.go | 4 ++-- storage/txcache/txListBySenderMap_test.go | 8 ++++++-- storage/txcache/txListForSender.go | 5 ----- storage/txcache/txListForSender_test.go | 5 ++--- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/storage/txcache/testutils_test.go b/storage/txcache/testutils_test.go index 7cac87d2f0..c694f24242 100644 --- a/storage/txcache/testutils_test.go +++ b/storage/txcache/testutils_test.go @@ -23,7 +23,11 @@ func kBToBytes(kB float32) uint64 { } func (cache *TxCache) getListForSender(sender string) *txListForSender { - list, ok := cache.txListBySender.getListForSender(sender) + return cache.txListBySender.testGetListForSender(sender) +} + +func (sendersMap *txListBySenderMap) testGetListForSender(sender string) *txListForSender { + list, ok := sendersMap.getListForSender(sender) if !ok { panic("sender not in cache") } diff --git a/storage/txcache/txListBySenderMap.go b/storage/txcache/txListBySenderMap.go index 3972f20cf6..1c6b7a2f14 100644 --- a/storage/txcache/txListBySenderMap.go +++ b/storage/txcache/txListBySenderMap.go @@ -75,8 +75,8 @@ func (txMap *txListBySenderMap) removeTx(tx *WrappedTransaction) bool { } isFound := listForSender.RemoveTx(tx) - - if listForSender.IsEmpty() { + isEmpty := listForSender.IsEmpty() + if isEmpty { txMap.removeSender(sender) } diff --git a/storage/txcache/txListBySenderMap_test.go b/storage/txcache/txListBySenderMap_test.go index 36d740659e..2962e96b67 100644 --- a/storage/txcache/txListBySenderMap_test.go +++ b/storage/txcache/txListBySenderMap_test.go @@ -22,17 +22,21 @@ func TestSendersMap_AddTx_IncrementsCounter(t *testing.T) { func TestSendersMap_RemoveTx_AlsoRemovesSenderWhenNoTransactionLeft(t *testing.T) { myMap := newSendersMapToTest() - txAlice1 := createTx([]byte("a"), "alice", uint64(1)) - txAlice2 := createTx([]byte("a"), "alice", uint64(2)) + txAlice1 := createTx([]byte("a1"), "alice", uint64(1)) + txAlice2 := createTx([]byte("a2"), "alice", uint64(2)) txBob := createTx([]byte("b"), "bob", uint64(1)) myMap.addTx(txAlice1) myMap.addTx(txAlice2) myMap.addTx(txBob) require.Equal(t, int64(2), myMap.counter.Get()) + require.Equal(t, uint64(2), myMap.testGetListForSender("alice").countTx()) + require.Equal(t, uint64(1), myMap.testGetListForSender("bob").countTx()) myMap.removeTx(txAlice1) require.Equal(t, int64(2), myMap.counter.Get()) + require.Equal(t, uint64(1), myMap.testGetListForSender("alice").countTx()) + require.Equal(t, uint64(1), myMap.testGetListForSender("bob").countTx()) myMap.removeTx(txAlice2) // All alice's transactions have been removed now diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index a111609dbb..04833233ce 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -181,11 +181,6 @@ func (listForSender *txListForSender) findListElementWithTx(txToFind *WrappedTra return nil } -// HasMoreThan checks whether the list has more items than specified -func (listForSender *txListForSender) HasMoreThan(count uint32) bool { - return uint32(listForSender.countTxWithLock()) > count -} - // IsEmpty checks whether the list is empty func (listForSender *txListForSender) IsEmpty() bool { return listForSender.countTxWithLock() == 0 diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 61ec88bfc2..ec1e841b50 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -263,10 +263,10 @@ func TestListForSender_hasInitialGap(t *testing.T) { // No transaction, no gap require.False(t, list.hasInitialGap()) // One gap - list.AddTx(createTx([]byte("tx-44"), ".", 43)) + list.AddTx(createTx([]byte("tx-43"), ".", 43)) require.True(t, list.hasInitialGap()) // Resolve gap - list.AddTx(createTx([]byte("tx-44"), ".", 42)) + list.AddTx(createTx([]byte("tx-42"), ".", 42)) require.False(t, list.hasInitialGap()) } @@ -288,7 +288,6 @@ func TestListForSender_DetectRaceConditions(t *testing.T) { go func() { // These are called concurrently with addition: during eviction, during removal etc. approximatelyCountTxInLists([]*txListForSender{list}) - list.HasMoreThan(42) list.IsEmpty() }() From 959d65b56bb5ede6cbaea2eb584aca3a18951a82 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 20:22:17 +0300 Subject: [PATCH 14/79] Verify cache config. Extract interface. Add disabled cache (for critical errors). --- dataRetriever/txpool/interface.go | 17 +++ dataRetriever/txpool/shardedTxPool.go | 19 ++- dataRetriever/txpool/shardedTxPool_test.go | 2 +- storage/txcache/config.go | 40 +++++++ storage/txcache/disabledCache.go | 127 +++++++++++++++++++++ storage/txcache/errors.go | 1 + storage/txcache/eviction_test.go | 38 ++++-- storage/txcache/monitoring_test.go | 8 +- storage/txcache/txCache.go | 10 +- storage/txcache/txCache_test.go | 17 ++- 10 files changed, 259 insertions(+), 20 deletions(-) create mode 100644 dataRetriever/txpool/interface.go create mode 100644 storage/txcache/disabledCache.go diff --git a/dataRetriever/txpool/interface.go b/dataRetriever/txpool/interface.go new file mode 100644 index 0000000000..5fcc747837 --- /dev/null +++ b/dataRetriever/txpool/interface.go @@ -0,0 +1,17 @@ +package txpool + +import ( + "github.com/ElrondNetwork/elrond-go/storage" + "github.com/ElrondNetwork/elrond-go/storage/txcache" +) + +type txCache interface { + storage.Cacher + + AddTx(tx *txcache.WrappedTransaction) (ok bool, added bool) + GetByTxHash(txHash []byte) (*txcache.WrappedTransaction, bool) + RemoveTxByHash(txHash []byte) error + CountTx() int64 + ForEachTransaction(function txcache.ForEachTransaction) + SelectTransactions(numRequested int, batchSizePerSender int) []*txcache.WrappedTransaction +} diff --git a/dataRetriever/txpool/shardedTxPool.go b/dataRetriever/txpool/shardedTxPool.go index 6c4bcfea46..66a966cb52 100644 --- a/dataRetriever/txpool/shardedTxPool.go +++ b/dataRetriever/txpool/shardedTxPool.go @@ -31,7 +31,7 @@ type shardedTxPool struct { type txPoolShard struct { CacheID string - Cache *txcache.TxCache + Cache txCache } // NewShardedTxPool creates a new sharded tx pool @@ -82,7 +82,7 @@ func (txPool *shardedTxPool) ShardDataStore(cacheID string) storage.Cacher { } // getTxCache returns the requested cache -func (txPool *shardedTxPool) getTxCache(cacheID string) *txcache.TxCache { +func (txPool *shardedTxPool) getTxCache(cacheID string) txCache { shard := txPool.getOrCreateShard(cacheID) return shard.Cache } @@ -108,8 +108,7 @@ func (txPool *shardedTxPool) createShard(cacheID string) *txPoolShard { shard, ok := txPool.backingMap[cacheID] if !ok { - cacheConfig := txPool.getCacheConfig(cacheID) - cache := txcache.NewTxCache(cacheConfig) + cache := txPool.createTxCache(cacheID) shard = &txPoolShard{ CacheID: cacheID, Cache: cache, @@ -121,6 +120,17 @@ func (txPool *shardedTxPool) createShard(cacheID string) *txPoolShard { return shard } +func (txPool *shardedTxPool) createTxCache(cacheID string) txCache { + cacheConfig := txPool.getCacheConfig(cacheID) + cache, err := txcache.NewTxCache(cacheConfig) + if err != nil { + log.Error("shardedTxPool.createTxCache()", "err", err) + return txcache.NewDisabledCache() + } + + return cache +} + func (txPool *shardedTxPool) getCacheConfig(cacheID string) txcache.CacheConfig { var cacheConfig txcache.CacheConfig @@ -144,6 +154,7 @@ func (txPool *shardedTxPool) AddData(key []byte, value interface{}, cacheID stri sourceShardID, destinationShardID, err := process.ParseShardCacherIdentifier(cacheID) if err != nil { + log.Error("shardedTxPool.AddData()", "err", err) return } diff --git a/dataRetriever/txpool/shardedTxPool_test.go b/dataRetriever/txpool/shardedTxPool_test.go index 7e1e91788d..820451668e 100644 --- a/dataRetriever/txpool/shardedTxPool_test.go +++ b/dataRetriever/txpool/shardedTxPool_test.go @@ -175,7 +175,7 @@ func Test_AddData_CallsOnAddedHandlers(t *testing.T) { // Second addition is ignored (txhash-based deduplication) pool.AddData([]byte("hash-1"), createTx("alice", 42), "1") - pool.AddData([]byte("hash-1"), createTx("whatever", 43), "1") + pool.AddData([]byte("hash-1"), createTx("alice", 42), "1") waitABit() require.Equal(t, uint32(1), atomic.LoadUint32(&numAdded)) diff --git a/storage/txcache/config.go b/storage/txcache/config.go index b4b4638e2b..9c0c276232 100644 --- a/storage/txcache/config.go +++ b/storage/txcache/config.go @@ -1,5 +1,7 @@ package txcache +import "fmt" + // CacheConfig holds cache configuration type CacheConfig struct { Name string @@ -12,3 +14,41 @@ type CacheConfig struct { NumSendersToEvictInOneStep uint32 MinGasPriceMicroErd uint32 } + +func (config *CacheConfig) verify() error { + if len(config.Name) == 0 { + return fmt.Errorf("%w: config.Name is invalid", errInvalidCacheConfig) + } + + if config.NumChunksHint == 0 { + return fmt.Errorf("%w: config.NumChunksHint is invalid", errInvalidCacheConfig) + } + + if config.NumBytesPerSenderThreshold == 0 { + return fmt.Errorf("%w: config.NumBytesPerSenderThreshold is invalid", errInvalidCacheConfig) + } + + if config.CountPerSenderThreshold == 0 { + return fmt.Errorf("%w: config.CountPerSenderThreshold is invalid", errInvalidCacheConfig) + } + + if config.MinGasPriceMicroErd == 0 { + return fmt.Errorf("%w: config.MinGasPriceMicroErd is invalid", errInvalidCacheConfig) + } + + if config.EvictionEnabled { + if config.NumBytesThreshold == 0 { + return fmt.Errorf("%w: config.NumBytesThreshold is invalid", errInvalidCacheConfig) + } + + if config.CountThreshold == 0 { + return fmt.Errorf("%w: config.CountThreshold is invalid", errInvalidCacheConfig) + } + + if config.NumSendersToEvictInOneStep == 0 { + return fmt.Errorf("%w: config.NumSendersToEvictInOneStep is invalid", errInvalidCacheConfig) + } + } + + return nil +} diff --git a/storage/txcache/disabledCache.go b/storage/txcache/disabledCache.go new file mode 100644 index 0000000000..a0a5ef6e7d --- /dev/null +++ b/storage/txcache/disabledCache.go @@ -0,0 +1,127 @@ +package txcache + +import ( + "github.com/ElrondNetwork/elrond-go/storage" +) + +var _ storage.Cacher = (*DisabledCache)(nil) + +// DisabledCache represents a disabled cache +type DisabledCache struct { +} + +// NewDisabledCache creates a new disabled cache +func NewDisabledCache() *DisabledCache { + return &DisabledCache{} +} + +// AddTx - +func (cache *DisabledCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { + log.Error("DisabledCache.AddTx()") + return false, false +} + +// GetByTxHash - +func (cache *DisabledCache) GetByTxHash(txHash []byte) (*WrappedTransaction, bool) { + log.Error("DisabledCache.GetByTxHash()") + return nil, false +} + +// SelectTransactions - +func (cache *DisabledCache) SelectTransactions(numRequested int, batchSizePerSender int) []*WrappedTransaction { + log.Error("DisabledCache.SelectTransactions()") + return make([]*WrappedTransaction, 0) +} + +// RemoveTxByHash - +func (cache *DisabledCache) RemoveTxByHash(txHash []byte) error { + log.Error("DisabledCache.RemoveTxByHash()") + return nil +} + +// CountTx - +func (cache *DisabledCache) CountTx() int64 { + log.Error("DisabledCache.CountTx()") + return 0 +} + +// Len - +func (cache *DisabledCache) Len() int { + log.Error("DisabledCache.Len()") + return 0 +} + +// ForEachTransaction - +func (cache *DisabledCache) ForEachTransaction(function ForEachTransaction) { + log.Error("DisabledCache.ForEachTransaction()") +} + +// Clear - +func (cache *DisabledCache) Clear() { + log.Error("DisabledCache.Clear()") +} + +// Put - +func (cache *DisabledCache) Put(key []byte, value interface{}) (evicted bool) { + log.Error("DisabledCache.Put()") + return false +} + +// Get - +func (cache *DisabledCache) Get(key []byte) (value interface{}, ok bool) { + tx, ok := cache.GetByTxHash(key) + if ok { + return tx.Tx, true + } + return nil, false +} + +// Has - +func (cache *DisabledCache) Has(key []byte) bool { + log.Error("DisabledCache.Has is not implemented") + return false +} + +// Peek - +func (cache *DisabledCache) Peek(key []byte) (value interface{}, ok bool) { + log.Error("DisabledCache.DisabledCache()") + return nil, false +} + +// HasOrAdd - +func (cache *DisabledCache) HasOrAdd(key []byte, value interface{}) (ok, evicted bool) { + log.Error("DisabledCache.HasOrAdd()") + return false, false +} + +// Remove - +func (cache *DisabledCache) Remove(key []byte) { + log.Error("DisabledCache.Remove()") +} + +// RemoveOldest - +func (cache *DisabledCache) RemoveOldest() { + log.Error("DisabledCache.RemoveOldest()") +} + +// Keys - +func (cache *DisabledCache) Keys() txHashes { + log.Error("DisabledCache.Keys()") + return make([][]byte, 0) +} + +// MaxSize - +func (cache *DisabledCache) MaxSize() int { + log.Error("DisabledCache.MaxSize()") + return 0 +} + +// RegisterHandler - +func (cache *DisabledCache) RegisterHandler(func(key []byte, value interface{})) { + log.Error("DisabledCache.RegisterHandler()") +} + +// IsInterfaceNil returns true if there is no value under the interface +func (cache *DisabledCache) IsInterfaceNil() bool { + return cache == nil +} diff --git a/storage/txcache/errors.go b/storage/txcache/errors.go index ba52ba431b..e58333db21 100644 --- a/storage/txcache/errors.go +++ b/storage/txcache/errors.go @@ -5,3 +5,4 @@ import "fmt" var errTxNotFound = fmt.Errorf("tx not found in cache") var errMapsSyncInconsistency = fmt.Errorf("maps sync inconsistency between 'txByHash' and 'txListBySender'") var errTxDuplicated = fmt.Errorf("duplicated tx") +var errInvalidCacheConfig = fmt.Errorf("invalid cache config") diff --git a/storage/txcache/eviction_test.go b/storage/txcache/eviction_test.go index f4acf5a3f2..ff111b2669 100644 --- a/storage/txcache/eviction_test.go +++ b/storage/txcache/eviction_test.go @@ -18,7 +18,9 @@ func TestEviction_EvictSendersWhileTooManyTxs(t *testing.T) { MinGasPriceMicroErd: 100, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) // 200 senders, each with 1 transaction for index := 0; index < 200; index++ { @@ -50,7 +52,9 @@ func TestEviction_EvictSendersWhileTooManyBytes(t *testing.T) { MinGasPriceMicroErd: 100, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) // 200 senders, each with 1 transaction for index := 0; index < 200; index++ { @@ -80,7 +84,10 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfCount(t *testing.T) { MinGasPriceMicroErd: 100, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 1000, 100000, 100*oneTrilion)) cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 1000, 100000, 100*oneTrilion)) cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 1000, 100000, 700*oneTrilion)) @@ -106,7 +113,10 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfSize(t *testing.T) { MinGasPriceMicroErd: 100, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 800, 100000, 100*oneTrilion)) cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 500, 100000, 100*oneTrilion)) cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 200, 100000, 700*oneTrilion)) @@ -134,7 +144,10 @@ func TestEviction_doEvictionDoesNothingWhenAlreadyInProgress(t *testing.T) { NumSendersToEvictInOneStep: 1, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + cache.AddTx(createTx([]byte("hash-alice"), "alice", uint64(1))) cache.isEvictionInProgress.Set() @@ -150,7 +163,10 @@ func TestEviction_evictSendersInLoop_CoverLoopBreak_WhenSmallBatch(t *testing.T) NumSendersToEvictInOneStep: 42, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + cache.AddTx(createTx([]byte("hash-alice"), "alice", uint64(1))) cache.makeSnapshotOfSenders() @@ -168,7 +184,10 @@ func TestEviction_evictSendersWhile_ShouldContinueBreak(t *testing.T) { NumSendersToEvictInOneStep: 1, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + cache.AddTx(createTx([]byte("hash-alice"), "alice", uint64(1))) cache.AddTx(createTx([]byte("hash-bob"), "bob", uint64(1))) @@ -198,7 +217,10 @@ func Test_AddWithEviction_UniformDistribution_25000x10(t *testing.T) { numSenders := 25000 numTxsPerSender := 10 - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + addManyTransactionsWithUniformDistribution(cache, numSenders, numTxsPerSender) // Sometimes (due to map iteration non-determinism), more eviction happens - one more step of 100 senders. diff --git a/storage/txcache/monitoring_test.go b/storage/txcache/monitoring_test.go index 257e5cb073..82154f5c5c 100644 --- a/storage/txcache/monitoring_test.go +++ b/storage/txcache/monitoring_test.go @@ -15,7 +15,9 @@ func TestMonitoring_numTxAddedAndRemovedDuringEviction(t *testing.T) { NumSendersToEvictInOneStep: 1, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) cache.isEvictionInProgress.Set() @@ -41,7 +43,9 @@ func TestMonitoring_numTxAddedAndRemovedBetweenSelections(t *testing.T) { NumSendersToEvictInOneStep: 1, } - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) require.Equal(t, int64(0), cache.numTxAddedBetweenSelections.Get()) diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index b05cdc490e..5628241a4a 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -31,9 +31,15 @@ type TxCache struct { } // NewTxCache creates a new transaction cache -func NewTxCache(config CacheConfig) *TxCache { +func NewTxCache(config CacheConfig) (*TxCache, error) { log.Debug("NewTxCache", "config", config) + err := config.verify() + if err != nil { + log.Error("NewTxCache config.verify()", "err", err) + return nil, err + } + // Note: for simplicity, we use the same "numChunksHint" for both internal concurrent maps numChunksHint := config.NumChunksHint @@ -46,7 +52,7 @@ func NewTxCache(config CacheConfig) *TxCache { } txCache.initSweepable() - return txCache + return txCache, nil } // AddTx adds a transaction in the cache diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index f5684808a9..4c5c98c2d2 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -249,7 +249,10 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { } // 11 * 10 - cache := NewTxCache(config) + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + addManyTransactionsWithUniformDistribution(cache, 11, 10) require.LessOrEqual(t, cache.CountTx(), int64(100)) @@ -262,7 +265,10 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { } // 100 * 1000 - cache = NewTxCache(config) + cache, err = NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + addManyTransactionsWithUniformDistribution(cache, 100, 1000) require.LessOrEqual(t, cache.CountTx(), int64(250000)) } @@ -336,5 +342,10 @@ func TestTxCache_ConcurrentMutationAndSelection(t *testing.T) { } func newCacheToTest() *TxCache { - return NewTxCache(CacheConfig{Name: "test", NumChunksHint: 16, MinGasPriceMicroErd: 100}) + cache, err := NewTxCache(CacheConfig{Name: "test", NumChunksHint: 16, MinGasPriceMicroErd: 100}) + if err != nil { + panic(fmt.Sprintf("newCacheToTest(): %s", err)) + } + + return cache } From e79c8ca1ca6364f296c4792d3d6e2274e1e0e506 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 11 May 2020 20:40:19 +0300 Subject: [PATCH 15/79] Fix tests. --- storage/txcache/eviction_test.go | 28 +++++++++++++++++++++++ storage/txcache/monitoring_test.go | 8 +++++++ storage/txcache/txCache_test.go | 16 ++++++++++++- storage/txcache/txListBySenderMap_test.go | 6 ++++- storage/txcache/txListForSender.go | 4 ++-- storage/txcache/txListForSender_test.go | 6 ++++- 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/storage/txcache/eviction_test.go b/storage/txcache/eviction_test.go index ff111b2669..57366378b9 100644 --- a/storage/txcache/eviction_test.go +++ b/storage/txcache/eviction_test.go @@ -11,10 +11,13 @@ import ( func TestEviction_EvictSendersWhileTooManyTxs(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, CountThreshold: 100, + CountPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 20, NumBytesThreshold: math.MaxUint32, + NumBytesPerSenderThreshold: math.MaxUint32, MinGasPriceMicroErd: 100, } @@ -45,9 +48,12 @@ func TestEviction_EvictSendersWhileTooManyBytes(t *testing.T) { numBytesPerTx := uint32(1000) config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, CountThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, NumBytesThreshold: numBytesPerTx * 100, + NumBytesPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 20, MinGasPriceMicroErd: 100, } @@ -77,9 +83,12 @@ func TestEviction_EvictSendersWhileTooManyBytes(t *testing.T) { func TestEviction_DoEvictionDoneInPassTwo_BecauseOfCount(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, NumBytesThreshold: math.MaxUint32, + NumBytesPerSenderThreshold: math.MaxUint32, CountThreshold: 2, + CountPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 2, MinGasPriceMicroErd: 100, } @@ -106,9 +115,12 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfCount(t *testing.T) { func TestEviction_DoEvictionDoneInPassTwo_BecauseOfSize(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, CountThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, NumBytesThreshold: 1000, + NumBytesPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 2, MinGasPriceMicroErd: 100, } @@ -139,9 +151,13 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfSize(t *testing.T) { func TestEviction_doEvictionDoesNothingWhenAlreadyInProgress(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 1, CountThreshold: 0, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } cache, err := NewTxCache(config) @@ -158,9 +174,13 @@ func TestEviction_doEvictionDoesNothingWhenAlreadyInProgress(t *testing.T) { func TestEviction_evictSendersInLoop_CoverLoopBreak_WhenSmallBatch(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 1, CountThreshold: 0, NumSendersToEvictInOneStep: 42, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } cache, err := NewTxCache(config) @@ -179,9 +199,13 @@ func TestEviction_evictSendersInLoop_CoverLoopBreak_WhenSmallBatch(t *testing.T) func TestEviction_evictSendersWhile_ShouldContinueBreak(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 1, CountThreshold: 0, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } cache, err := NewTxCache(config) @@ -207,11 +231,15 @@ func TestEviction_evictSendersWhile_ShouldContinueBreak(t *testing.T) { // ~1 second on average laptop. func Test_AddWithEviction_UniformDistribution_25000x10(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, EvictionEnabled: true, NumBytesThreshold: 1000000000, CountThreshold: 240000, NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } numSenders := 25000 diff --git a/storage/txcache/monitoring_test.go b/storage/txcache/monitoring_test.go index 82154f5c5c..4e1988ccfa 100644 --- a/storage/txcache/monitoring_test.go +++ b/storage/txcache/monitoring_test.go @@ -9,10 +9,14 @@ import ( func TestMonitoring_numTxAddedAndRemovedDuringEviction(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, CountThreshold: math.MaxUint32, NumBytesThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } cache, err := NewTxCache(config) @@ -37,10 +41,14 @@ func TestMonitoring_numTxAddedAndRemovedDuringEviction(t *testing.T) { func TestMonitoring_numTxAddedAndRemovedBetweenSelections(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, CountThreshold: math.MaxUint32, NumBytesThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } cache, err := NewTxCache(config) diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index 4c5c98c2d2..91522a9d57 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -241,11 +241,15 @@ func Test_Keys(t *testing.T) { func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { config := CacheConfig{ + Name: "untitled", NumChunksHint: 16, EvictionEnabled: true, NumBytesThreshold: math.MaxUint32, CountThreshold: 100, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } // 11 * 10 @@ -257,11 +261,15 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { require.LessOrEqual(t, cache.CountTx(), int64(100)) config = CacheConfig{ + Name: "untitled", NumChunksHint: 16, EvictionEnabled: true, NumBytesThreshold: math.MaxUint32, CountThreshold: 250000, NumSendersToEvictInOneStep: 1, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, } // 100 * 1000 @@ -342,7 +350,13 @@ func TestTxCache_ConcurrentMutationAndSelection(t *testing.T) { } func newCacheToTest() *TxCache { - cache, err := NewTxCache(CacheConfig{Name: "test", NumChunksHint: 16, MinGasPriceMicroErd: 100}) + cache, err := NewTxCache(CacheConfig{ + Name: "test", + NumChunksHint: 16, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, + }) if err != nil { panic(fmt.Sprintf("newCacheToTest(): %s", err)) } diff --git a/storage/txcache/txListBySenderMap_test.go b/storage/txcache/txListBySenderMap_test.go index 2962e96b67..d97fff3c6a 100644 --- a/storage/txcache/txListBySenderMap_test.go +++ b/storage/txcache/txListBySenderMap_test.go @@ -2,6 +2,7 @@ package txcache import ( "fmt" + "math" "sync" "testing" @@ -175,5 +176,8 @@ func createTxListBySenderMap(numSenders int) txListBySenderMap { } func newSendersMapToTest() txListBySenderMap { - return newTxListBySenderMap(4, CacheConfig{}) + return newTxListBySenderMap(4, CacheConfig{ + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + }) } diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 04833233ce..e20ff772bc 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -91,8 +91,8 @@ func (listForSender *txListForSender) applyLimit() txHashes { func (listForSender *txListForSender) isLimitReached() bool { maxBytes := int64(listForSender.cacheConfig.NumBytesPerSenderThreshold) maxNumTxs := uint64(listForSender.cacheConfig.CountPerSenderThreshold) - tooManyBytes := maxBytes > 0 && listForSender.totalBytes.Get() > maxBytes - tooManyTxs := maxNumTxs > 0 && listForSender.countTx() > maxNumTxs + tooManyBytes := listForSender.totalBytes.Get() > maxBytes + tooManyTxs := listForSender.countTx() > maxNumTxs return tooManyBytes || tooManyTxs } diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index ec1e841b50..07176f95fa 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -297,5 +297,9 @@ func TestListForSender_DetectRaceConditions(t *testing.T) { } func newListToTest() *txListForSender { - return newTxListForSender(".", &CacheConfig{MinGasPriceMicroErd: 100}, func(value *txListForSender) {}) + return newTxListForSender(".", &CacheConfig{ + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, + }, func(value *txListForSender) {}) } From 10f74e8fe00d9115dfffe4c89a028c89040ca86d Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 11:16:45 +0300 Subject: [PATCH 16/79] Fix remaining mock. --- genesis/mock/poolsHolderMock.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/genesis/mock/poolsHolderMock.go b/genesis/mock/poolsHolderMock.go index 89f8ac9b3b..9bd448e8c1 100644 --- a/genesis/mock/poolsHolderMock.go +++ b/genesis/mock/poolsHolderMock.go @@ -30,9 +30,11 @@ func NewPoolsHolderMock() *PoolsHolderMock { phf.transactions, _ = txpool.NewShardedTxPool( txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ - Size: 10000, - SizeInBytes: 1000000000, - Shards: 16, + Size: 100000, + SizePerSender: 1000, + SizeInBytes: 1000000000, + SizeInBytesPerSender: 10000000, + Shards: 16, }, MinGasPrice: 100000000000000, NumberOfShards: 1, From 19e7eb1ee356c0e971de7aa82a7650ae3301d652 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 13:03:20 +0300 Subject: [PATCH 17/79] Add some tests. --- storage/txcache/testutils_test.go | 15 +++ storage/txcache/txListForSender.go | 4 +- .../txListForSenderAsSortedMapItem_test.go | 4 +- storage/txcache/txListForSender_test.go | 118 +++++++++++++----- 4 files changed, 104 insertions(+), 37 deletions(-) diff --git a/storage/txcache/testutils_test.go b/storage/txcache/testutils_test.go index db29c01cbf..46a4d56635 100644 --- a/storage/txcache/testutils_test.go +++ b/storage/txcache/testutils_test.go @@ -53,6 +53,21 @@ func (cache *TxCache) isSenderSweepable(sender string) bool { return false } +func (listForSender *txListForSender) getTxHashesAsStrings() []string { + hashes := listForSender.getTxHashes() + return hashesAsStrings(hashes) +} + +func hashesAsStrings(hashes txHashes) []string { + result := make([]string, len(hashes)) + + for i := 0; i < len(hashes); i++ { + result[i] = string(hashes[i]) + } + + return result +} + func addManyTransactionsWithUniformDistribution(cache *TxCache, nSenders int, nTransactionsPerSender int) { for senderTag := 0; senderTag < nSenders; senderTag++ { sender := createFakeSenderAddress(senderTag) diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index e20ff772bc..07e4370802 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -62,14 +62,14 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) (bool, txHas } listForSender.onAddedTransaction(tx) - evicted := listForSender.applyLimit() + evicted := listForSender.applySizeConstraints() listForSender.triggerScoreChange() return true, evicted } // This function should only be used in critical section (listForSender.mutex) -func (listForSender *txListForSender) applyLimit() txHashes { +func (listForSender *txListForSender) applySizeConstraints() txHashes { evictedTxHashes := make(txHashes, 0) for element := listForSender.items.Back(); element != nil; element = element.Prev() { diff --git a/storage/txcache/txListForSenderAsSortedMapItem_test.go b/storage/txcache/txListForSenderAsSortedMapItem_test.go index b94a055f75..2841954609 100644 --- a/storage/txcache/txListForSenderAsSortedMapItem_test.go +++ b/storage/txcache/txListForSenderAsSortedMapItem_test.go @@ -7,7 +7,7 @@ import ( ) func TestSenderAsBucketSortedMapItem_ComputeScore(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.AddTx(createTxWithParams([]byte("a"), ".", 1, 1000, 200000, 100*oneTrilion)) list.AddTx(createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneTrilion)) @@ -22,7 +22,7 @@ func TestSenderAsBucketSortedMapItem_ComputeScore(t *testing.T) { } func TestSenderAsBucketSortedMapItem_ScoreFluctuatesDeterministicallyWhenTransactionsAreAddedOrRemoved(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() A := createTxWithParams([]byte("A"), ".", 1, 1000, 200000, 100*oneTrilion) B := createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneTrilion) diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 07176f95fa..fac3ac8712 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -8,26 +8,18 @@ import ( ) func TestListForSender_AddTx_Sorts(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.AddTx(createTx([]byte("a"), ".", 1)) list.AddTx(createTx([]byte("c"), ".", 3)) list.AddTx(createTx([]byte("d"), ".", 4)) list.AddTx(createTx([]byte("b"), ".", 2)) - txHashes := list.getTxHashes() - - require.Equal(t, 4, list.items.Len()) - require.Equal(t, 4, len(txHashes)) - - require.Equal(t, []byte("a"), txHashes[0]) - require.Equal(t, []byte("b"), txHashes[1]) - require.Equal(t, []byte("c"), txHashes[2]) - require.Equal(t, []byte("d"), txHashes[3]) + require.ElementsMatch(t, []string{"a", "b", "c", "d"}, list.getTxHashesAsStrings()) } func TestListForSender_AddTx_GivesPriorityToHigherGas(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.AddTx(createTxWithParams([]byte("a"), ".", 1, 128, 42, 42)) list.AddTx(createTxWithParams([]byte("b"), ".", 3, 128, 42, 100)) @@ -35,20 +27,72 @@ func TestListForSender_AddTx_GivesPriorityToHigherGas(t *testing.T) { list.AddTx(createTxWithParams([]byte("d"), ".", 2, 128, 42, 42)) list.AddTx(createTxWithParams([]byte("e"), ".", 3, 128, 42, 101)) - txHashes := list.getTxHashes() + require.ElementsMatch(t, []string{"a", "d", "e", "b", "c"}, list.getTxHashesAsStrings()) +} + +func TestListForSender_AddTx_IgnoresDuplicates(t *testing.T) { + list := newUnconstrainedListToTest() + + added, _ := list.AddTx(createTx([]byte("tx1"), ".", 1)) + require.True(t, added) + added, _ = list.AddTx(createTx([]byte("tx2"), ".", 2)) + require.True(t, added) + added, _ = list.AddTx(createTx([]byte("tx3"), ".", 3)) + require.True(t, added) + added, _ = list.AddTx(createTx([]byte("tx2"), ".", 2)) + require.False(t, added) +} + +func TestListForSender_AddTx_AppliesSizeConstraints_Count(t *testing.T) { + list := newListToTest(math.MaxUint32, 3) + + list.AddTx(createTx([]byte("tx1"), ".", 1)) + list.AddTx(createTx([]byte("tx5"), ".", 5)) + list.AddTx(createTx([]byte("tx4"), ".", 4)) + list.AddTx(createTx([]byte("tx2"), ".", 2)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx4"}, list.getTxHashesAsStrings()) + + _, evicted := list.AddTx(createTx([]byte("tx3"), ".", 3)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) - require.Equal(t, 5, list.items.Len()) - require.Equal(t, 5, len(txHashes)) + // Gives priority to higher gas - undesirably to some extent, "tx3" is evicted + _, evicted = list.AddTx(createTxWithParams([]byte("tx2++"), ".", 2, 128, 42, 42)) + require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx3"}, hashesAsStrings(evicted)) - require.Equal(t, []byte("a"), txHashes[0]) - require.Equal(t, []byte("d"), txHashes[1]) - require.Equal(t, []byte("e"), txHashes[2]) - require.Equal(t, []byte("b"), txHashes[3]) - require.Equal(t, []byte("c"), txHashes[4]) + // Undesirably to some extent, "tx3++"" is added, then evicted + _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 3, 128, 42, 42)) + require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx3++"}, hashesAsStrings(evicted)) +} + +func TestListForSender_AddTx_AppliesSizeConstraints_SizeInBytes(t *testing.T) { + list := newListToTest(1024, math.MaxUint32) + + list.AddTx(createTxWithParams([]byte("tx1"), ".", 1, 128, 42, 42)) + list.AddTx(createTxWithParams([]byte("tx2"), ".", 2, 512, 42, 42)) + list.AddTx(createTxWithParams([]byte("tx3"), ".", 3, 256, 42, 42)) + _, evicted := list.AddTx(createTxWithParams([]byte("tx5"), ".", 4, 256, 42, 42)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx5"}, hashesAsStrings(evicted)) + + _, evicted = list.AddTx(createTxWithParams([]byte("tx5--"), ".", 4, 128, 42, 42)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx3", "tx5--"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{}, hashesAsStrings(evicted)) + + _, evicted = list.AddTx(createTxWithParams([]byte("tx4"), ".", 4, 128, 42, 42)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx3", "tx4"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx5--"}, hashesAsStrings(evicted)) + + // Gives priority to higher gas - undesirably to some extent, "tx4" is evicted + _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 4, 256, 42, 100)) + require.ElementsMatch(t, []string{"tx1", "tx2", "tx3++", "tx3"}, list.getTxHashesAsStrings()) + require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) } func TestListForSender_findTx(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() txA := createTx([]byte("A"), ".", 41) txANewer := createTx([]byte("ANewer"), ".", 41) @@ -74,7 +118,7 @@ func TestListForSender_findTx(t *testing.T) { } func TestListForSender_findTx_CoverNonceComparisonOptimization(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.AddTx(createTx([]byte("A"), ".", 42)) // Find one with a lower nonce, not added to cache @@ -83,7 +127,7 @@ func TestListForSender_findTx_CoverNonceComparisonOptimization(t *testing.T) { } func TestListForSender_RemoveTransaction(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() tx := createTx([]byte("a"), ".", 1) list.AddTx(tx) @@ -94,7 +138,7 @@ func TestListForSender_RemoveTransaction(t *testing.T) { } func TestListForSender_RemoveTransaction_NoPanicWhenTxMissing(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() tx := createTx([]byte(""), ".", 1) list.RemoveTx(tx) @@ -102,7 +146,7 @@ func TestListForSender_RemoveTransaction_NoPanicWhenTxMissing(t *testing.T) { } func TestListForSender_SelectBatchTo(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() for index := 0; index < 100; index++ { list.AddTx(createTx([]byte{byte(index)}, ".", uint64(index))) @@ -131,7 +175,7 @@ func TestListForSender_SelectBatchTo(t *testing.T) { } func TestListForSender_SelectBatchTo_NoPanicWhenCornerCases(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() for index := 0; index < 100; index++ { list.AddTx(createTx([]byte{byte(index)}, ".", uint64(index))) @@ -149,7 +193,7 @@ func TestListForSender_SelectBatchTo_NoPanicWhenCornerCases(t *testing.T) { } func TestListForSender_SelectBatchTo_WhenInitialGap(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.notifyAccountNonce(1) @@ -180,7 +224,7 @@ func TestListForSender_SelectBatchTo_WhenInitialGap(t *testing.T) { } func TestListForSender_SelectBatchTo_WhenGracePeriodWithGapResolve(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.notifyAccountNonce(1) @@ -213,7 +257,7 @@ func TestListForSender_SelectBatchTo_WhenGracePeriodWithGapResolve(t *testing.T) } func TestListForSender_SelectBatchTo_WhenGracePeriodWithNoGapResolve(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.notifyAccountNonce(1) @@ -245,7 +289,7 @@ func TestListForSender_SelectBatchTo_WhenGracePeriodWithNoGapResolve(t *testing. } func TestListForSender_NotifyAccountNonce(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() require.Equal(t, uint64(0), list.accountNonce.Get()) require.False(t, list.accountNonceKnown.IsSet()) @@ -257,7 +301,7 @@ func TestListForSender_NotifyAccountNonce(t *testing.T) { } func TestListForSender_hasInitialGap(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() list.notifyAccountNonce(42) // No transaction, no gap @@ -271,7 +315,7 @@ func TestListForSender_hasInitialGap(t *testing.T) { } func TestListForSender_getTxHashes(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() require.Len(t, list.getTxHashes(), 0) list.AddTx(createTx([]byte("A"), ".", 1)) @@ -283,7 +327,7 @@ func TestListForSender_getTxHashes(t *testing.T) { } func TestListForSender_DetectRaceConditions(t *testing.T) { - list := newListToTest() + list := newUnconstrainedListToTest() go func() { // These are called concurrently with addition: during eviction, during removal etc. @@ -296,10 +340,18 @@ func TestListForSender_DetectRaceConditions(t *testing.T) { }() } -func newListToTest() *txListForSender { +func newUnconstrainedListToTest() *txListForSender { return newTxListForSender(".", &CacheConfig{ NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, MinGasPriceMicroErd: 100, }, func(value *txListForSender) {}) } + +func newListToTest(numBytesThreshold uint32, countThreshold uint32) *txListForSender { + return newTxListForSender(".", &CacheConfig{ + NumBytesPerSenderThreshold: numBytesThreshold, + CountPerSenderThreshold: countThreshold, + MinGasPriceMicroErd: 100, + }, func(value *txListForSender) {}) +} From 1e60467e9855cd8888460bc6490abc026cee66ae Mon Sep 17 00:00:00 2001 From: bogdan-rosianu Date: Tue, 12 May 2020 13:55:53 +0300 Subject: [PATCH 18/79] EN-6411: unit tests epoch start bootstrap and update --- epochStart/bootstrap/export_test.go | 4 + epochStart/bootstrap/interface.go | 10 +- epochStart/bootstrap/syncEpochStartMeta.go | 2 +- .../bootstrap/syncEpochStartMeta_test.go | 115 +++++++++++ .../bootstrap/syncValidatorStatus_test.go | 146 ++++++++++++++ epochStart/mock/messengerStub.go | 7 +- update/container/accountDBSyncers_test.go | 102 ++++++++++ update/container/trieSyncers_test.go | 103 ++++++++++ update/sync/base_test.go | 67 +++++++ update/sync/concurrentTriesMap_test.go | 61 ++++++ update/sync/syncHeadersByHash.go | 2 +- update/sync/syncHeadersByHash_test.go | 179 ++++++++++++++++++ update/sync/syncMiniBlocks_test.go | 106 +++++++++++ 13 files changed, 897 insertions(+), 7 deletions(-) create mode 100644 epochStart/bootstrap/syncEpochStartMeta_test.go create mode 100644 epochStart/bootstrap/syncValidatorStatus_test.go create mode 100644 update/container/accountDBSyncers_test.go create mode 100644 update/container/trieSyncers_test.go create mode 100644 update/sync/base_test.go create mode 100644 update/sync/concurrentTriesMap_test.go create mode 100644 update/sync/syncHeadersByHash_test.go diff --git a/epochStart/bootstrap/export_test.go b/epochStart/bootstrap/export_test.go index f885f76ccb..b582242118 100644 --- a/epochStart/bootstrap/export_test.go +++ b/epochStart/bootstrap/export_test.go @@ -6,6 +6,10 @@ import ( "github.com/ElrondNetwork/elrond-go/storage/storageUnit" ) +func (e *epochStartMetaSyncer) SetEpochStartMetaBlockInterceptorProcessor(proc EpochStartMetaBlockInterceptorProcessor) { + e.metaBlockProcessor = proc +} + // TODO: We should remove this type of configs hidden in tests func getGeneralConfig() config.Config { return config.Config{ diff --git a/epochStart/bootstrap/interface.go b/epochStart/bootstrap/interface.go index 8a564cea3b..f665ea1798 100644 --- a/epochStart/bootstrap/interface.go +++ b/epochStart/bootstrap/interface.go @@ -1,6 +1,8 @@ package bootstrap import ( + "context" + "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/dataRetriever" @@ -15,10 +17,10 @@ type StartOfEpochNodesConfigHandler interface { IsInterfaceNil() bool } -// EpochStartInterceptor defines the methods to sync an epoch start metablock -type EpochStartInterceptor interface { - process.Interceptor - GetEpochStartMetaBlock(target int, epoch uint32) (*block.MetaBlock, error) +// EpochStartMetaBlockInterceptorProcessor defines the methods to sync an epoch start metablock +type EpochStartMetaBlockInterceptorProcessor interface { + process.InterceptorProcessor + GetEpochStartMetaBlock(ctx context.Context) (*block.MetaBlock, error) } // StartInEpochNodesCoordinator defines the methods to process and save nodesCoordinator information to storage diff --git a/epochStart/bootstrap/syncEpochStartMeta.go b/epochStart/bootstrap/syncEpochStartMeta.go index 64646bc07f..d8ca3b10d4 100644 --- a/epochStart/bootstrap/syncEpochStartMeta.go +++ b/epochStart/bootstrap/syncEpochStartMeta.go @@ -29,7 +29,7 @@ type epochStartMetaSyncer struct { marshalizer marshal.Marshalizer hasher hashing.Hasher singleDataInterceptor process.Interceptor - metaBlockProcessor *epochStartMetaBlockProcessor + metaBlockProcessor EpochStartMetaBlockInterceptorProcessor } // ArgsNewEpochStartMetaSyncer - diff --git a/epochStart/bootstrap/syncEpochStartMeta_test.go b/epochStart/bootstrap/syncEpochStartMeta_test.go new file mode 100644 index 0000000000..bc3e0e731b --- /dev/null +++ b/epochStart/bootstrap/syncEpochStartMeta_test.go @@ -0,0 +1,115 @@ +package bootstrap + +import ( + "errors" + "testing" + "time" + + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/data/block" + "github.com/ElrondNetwork/elrond-go/epochStart/mock" + "github.com/ElrondNetwork/elrond-go/p2p" + "github.com/ElrondNetwork/elrond-go/process/economics" + "github.com/stretchr/testify/require" +) + +func TestNewEpochStartMetaSyncer_ShouldWork(t *testing.T) { + t.Parallel() + + args := getEpochStartSyncerArgs() + ess, err := NewEpochStartMetaSyncer(args) + require.NoError(t, err) + require.False(t, check.IfNil(ess)) +} + +func TestEpochStartMetaSyncer_SyncEpochStartMeta_ErrRegisterMessengerProcessorShouldErr(t *testing.T) { + t.Parallel() + + expectedErr := errors.New("expected error") + + args := getEpochStartSyncerArgs() + messenger := &mock.MessengerStub{ + RegisterMessageProcessorCalled: func(_ string, _ p2p.MessageProcessor) error { + return expectedErr + }, + } + args.Messenger = messenger + ess, _ := NewEpochStartMetaSyncer(args) + + mb, err := ess.SyncEpochStartMeta(1 * time.Second) + require.Equal(t, expectedErr, err) + require.Nil(t, mb) +} + +func TestEpochStartMetaSyncer_SyncEpochStartMeta_ProcessorReturnsErrorShouldErr(t *testing.T) { + t.Parallel() + + expectedErr := errors.New("expected error") + + args := getEpochStartSyncerArgs() + messenger := &mock.MessengerStub{ + ConnectedPeersCalled: func() []p2p.PeerID { + return []p2p.PeerID{"peer_0", "peer_1", "peer_2", "peer_3", "peer_4", "peer_5"} + }, + } + args.Messenger = messenger + ess, _ := NewEpochStartMetaSyncer(args) + + mbIntercProc := &mock.MetaBlockInterceptorProcessorStub{ + GetEpochStartMetaBlockCalled: func() (*block.MetaBlock, error) { + return nil, expectedErr + }, + } + ess.SetEpochStartMetaBlockInterceptorProcessor(mbIntercProc) + + mb, err := ess.SyncEpochStartMeta(1 * time.Second) + require.Equal(t, expectedErr, err) + require.Nil(t, mb) +} + +func TestEpochStartMetaSyncer_SyncEpochStartMeta_ShouldWork(t *testing.T) { + t.Parallel() + + expectedMb := &block.MetaBlock{Nonce: 37} + + args := getEpochStartSyncerArgs() + messenger := &mock.MessengerStub{ + ConnectedPeersCalled: func() []p2p.PeerID { + return []p2p.PeerID{"peer_0", "peer_1", "peer_2", "peer_3", "peer_4", "peer_5"} + }, + } + args.Messenger = messenger + ess, _ := NewEpochStartMetaSyncer(args) + + mbIntercProc := &mock.MetaBlockInterceptorProcessorStub{ + GetEpochStartMetaBlockCalled: func() (*block.MetaBlock, error) { + return expectedMb, nil + }, + } + ess.SetEpochStartMetaBlockInterceptorProcessor(mbIntercProc) + + mb, err := ess.SyncEpochStartMeta(1 * time.Second) + require.NoError(t, err) + require.Equal(t, expectedMb, mb) +} + +func getEpochStartSyncerArgs() ArgsNewEpochStartMetaSyncer { + return ArgsNewEpochStartMetaSyncer{ + RequestHandler: &mock.RequestHandlerStub{}, + Messenger: &mock.MessengerStub{}, + Marshalizer: &mock.MarshalizerMock{}, + TxSignMarshalizer: &mock.MarshalizerMock{}, + ShardCoordinator: mock.NewMultiShardsCoordinatorMock(2), + KeyGen: &mock.KeyGenMock{}, + BlockKeyGen: &mock.KeyGenMock{}, + Hasher: &mock.HasherMock{}, + Signer: &mock.SignerStub{}, + BlockSigner: &mock.SignerStub{}, + ChainID: []byte("chain-ID"), + EconomicsData: &economics.EconomicsData{}, + WhitelistHandler: &mock.WhiteListHandlerStub{}, + AddressPubkeyConv: mock.NewPubkeyConverterMock(32), + NonceConverter: &mock.Uint64ByteSliceConverterMock{}, + } + +} diff --git a/epochStart/bootstrap/syncValidatorStatus_test.go b/epochStart/bootstrap/syncValidatorStatus_test.go new file mode 100644 index 0000000000..60a3c97fcf --- /dev/null +++ b/epochStart/bootstrap/syncValidatorStatus_test.go @@ -0,0 +1,146 @@ +package bootstrap + +import ( + "testing" + + "github.com/ElrondNetwork/elrond-go/core" + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/data/block" + "github.com/ElrondNetwork/elrond-go/epochStart/mock" + "github.com/ElrondNetwork/elrond-go/sharding" + "github.com/ElrondNetwork/elrond-go/storage" + "github.com/stretchr/testify/require" +) + +func TestNewSyncValidatorStatus_ShouldWork(t *testing.T) { + t.Parallel() + + args := getSyncValidatorStatusArgs() + svs, err := NewSyncValidatorStatus(args) + require.NoError(t, err) + require.False(t, check.IfNil(svs)) +} + +func TestSyncValidatorStatus_NodesConfigFromMetaBlock(t *testing.T) { + t.Parallel() + + args := getSyncValidatorStatusArgs() + svs, _ := NewSyncValidatorStatus(args) + + currMb := &block.MetaBlock{ + Nonce: 37, + Epoch: 0, + MiniBlockHeaders: []block.MiniBlockHeader{ + { + Hash: []byte("mb0-hash"), + ReceiverShardID: 0, + SenderShardID: 0, + Type: block.TxBlock, + TxCount: 0, + }, + }, + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + { + ShardID: 0, + Epoch: 0, + Round: 0, + Nonce: 0, + HeaderHash: []byte("hash"), + RootHash: []byte("rootHash"), + FirstPendingMetaBlock: []byte("hash"), + LastFinishedMetaBlock: []byte("hash"), + PendingMiniBlockHeaders: nil, + }, + }, + }} + prevMb := &block.MetaBlock{ + Nonce: 36, + Epoch: 0, + MiniBlockHeaders: []block.MiniBlockHeader{ + { + Hash: []byte("mb0-hash"), + ReceiverShardID: 0, + SenderShardID: 0, + Type: block.TxBlock, + TxCount: 0, + }, + }, + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + { + ShardID: 0, + Epoch: 0, + Round: 0, + Nonce: 0, + HeaderHash: []byte("hash"), + RootHash: []byte("rootHash"), + FirstPendingMetaBlock: []byte("hash"), + LastFinishedMetaBlock: []byte("hash"), + PendingMiniBlockHeaders: nil, + }, + }, + }} + registry, _, err := svs.NodesConfigFromMetaBlock(currMb, prevMb) + require.NoError(t, err) + require.NotNil(t, registry) +} + +func getSyncValidatorStatusArgs() ArgsNewSyncValidatorStatus { + return ArgsNewSyncValidatorStatus{ + DataPool: &mock.PoolsHolderStub{ + MiniBlocksCalled: func() storage.Cacher { + return &mock.CacherStub{} + }, + }, + Marshalizer: &mock.MarshalizerMock{}, + Hasher: &mock.HasherMock{}, + RequestHandler: &mock.RequestHandlerStub{}, + ChanceComputer: &mock.NodesCoordinatorStub{}, + GenesisNodesConfig: &mock.NodesSetupStub{ + NumberOfShardsCalled: func() uint32 { + return 1 + }, + InitialNodesInfoForShardCalled: func(shardID uint32) ([]sharding.GenesisNodeInfoHandler, []sharding.GenesisNodeInfoHandler, error) { + if shardID == core.MetachainShardId { + return []sharding.GenesisNodeInfoHandler{ + mock.NewNodeInfo([]byte("addr0"), []byte("pubKey0"), core.MetachainShardId), + mock.NewNodeInfo([]byte("addr1"), []byte("pubKey1"), core.MetachainShardId), + }, + []sharding.GenesisNodeInfoHandler{&mock.NodeInfoMock{}}, + nil + } + return []sharding.GenesisNodeInfoHandler{ + mock.NewNodeInfo([]byte("addr0"), []byte("pubKey0"), 0), + mock.NewNodeInfo([]byte("addr1"), []byte("pubKey1"), 0), + }, + []sharding.GenesisNodeInfoHandler{&mock.NodeInfoMock{}}, + nil + }, + InitialNodesInfoCalled: func() (map[uint32][]sharding.GenesisNodeInfoHandler, map[uint32][]sharding.GenesisNodeInfoHandler) { + return map[uint32][]sharding.GenesisNodeInfoHandler{ + 0: { + mock.NewNodeInfo([]byte("addr0"), []byte("pubKey0"), 0), + mock.NewNodeInfo([]byte("addr1"), []byte("pubKey1"), 0), + }, + core.MetachainShardId: { + mock.NewNodeInfo([]byte("addr0"), []byte("pubKey0"), core.MetachainShardId), + mock.NewNodeInfo([]byte("addr1"), []byte("pubKey1"), core.MetachainShardId), + }, + }, map[uint32][]sharding.GenesisNodeInfoHandler{0: { + mock.NewNodeInfo([]byte("addr2"), []byte("pubKey2"), 0), + mock.NewNodeInfo([]byte("addr3"), []byte("pubKey3"), 0), + }} + }, + GetShardConsensusGroupSizeCalled: func() uint32 { + return 2 + }, + GetMetaConsensusGroupSizeCalled: func() uint32 { + return 2 + }, + }, + NodeShuffler: &mock.NodeShufflerMock{}, + PubKey: []byte("public key"), + ShardIdAsObserver: 0, + } +} diff --git a/epochStart/mock/messengerStub.go b/epochStart/mock/messengerStub.go index 55b7ad54f4..f9a10f57f2 100644 --- a/epochStart/mock/messengerStub.go +++ b/epochStart/mock/messengerStub.go @@ -6,7 +6,8 @@ import ( // MessengerStub - type MessengerStub struct { - ConnectedPeersCalled func() []p2p.PeerID + ConnectedPeersCalled func() []p2p.PeerID + RegisterMessageProcessorCalled func(topic string, handler p2p.MessageProcessor) error } // ConnectedPeersOnTopic - @@ -36,6 +37,10 @@ func (m *MessengerStub) CreateTopic(name string, createChannelForTopic bool) err // RegisterMessageProcessor - func (m *MessengerStub) RegisterMessageProcessor(topic string, handler p2p.MessageProcessor) error { + if m.RegisterMessageProcessorCalled != nil { + return m.RegisterMessageProcessorCalled(topic, handler) + } + return nil } diff --git a/update/container/accountDBSyncers_test.go b/update/container/accountDBSyncers_test.go new file mode 100644 index 0000000000..dc307885a5 --- /dev/null +++ b/update/container/accountDBSyncers_test.go @@ -0,0 +1,102 @@ +package containers + +import ( + "errors" + "testing" + + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/update" + "github.com/ElrondNetwork/elrond-go/update/mock" + "github.com/stretchr/testify/require" +) + +func TestNewAccountsDBSyncersContainer(t *testing.T) { + t.Parallel() + + adsc := NewAccountsDBSyncersContainer() + require.False(t, check.IfNil(adsc)) +} + +func TestAccountDBSyncers_AddGetShouldWork(t *testing.T) { + t.Parallel() + + adsc := NewAccountsDBSyncersContainer() + testKey := "key" + testVal := &mock.AccountsDBSyncerStub{} + err := adsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := adsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) +} + +func TestAccountDBSyncers_AddMultipleShouldWork(t *testing.T) { + t.Parallel() + + adsc := NewAccountsDBSyncersContainer() + testKey0 := "key0" + testVal0 := &mock.AccountsDBSyncerStub{} + testKey1 := "key1" + testVal1 := &mock.AccountsDBSyncerStub{} + + err := adsc.AddMultiple([]string{testKey0, testKey1}, []update.AccountsDBSyncer{testVal0, testVal1}) + require.NoError(t, err) + + res0, err := adsc.Get(testKey0) + require.NoError(t, err) + require.Equal(t, testVal0, res0) + + res1, err := adsc.Get(testKey1) + require.NoError(t, err) + require.Equal(t, testVal1, res1) + + require.Equal(t, 2, adsc.Len()) +} + +func TestAccountDBSyncers_ReplaceShouldWork(t *testing.T) { + t.Parallel() + + adsc := NewAccountsDBSyncersContainer() + testKey := "key" + testVal := &mock.AccountsDBSyncerStub{} + err := adsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := adsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) + + // update + newTestVal := &mock.AccountsDBSyncerStub{ + SyncAccountsCalled: func(_ []byte) error { + return errors.New("local error") + }, + } + err = adsc.Replace(testKey, newTestVal) + require.NoError(t, err) + + res, err = adsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, newTestVal, res) +} + +func TestAccountDBSyncers_DeleteShouldWork(t *testing.T) { + t.Parallel() + + adsc := NewAccountsDBSyncersContainer() + testKey := "key" + testVal := &mock.AccountsDBSyncerStub{} + err := adsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := adsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) + + adsc.Remove(testKey) + + res, err = adsc.Get(testKey) + require.Nil(t, res) + require.Equal(t, update.ErrInvalidContainerKey, err) +} diff --git a/update/container/trieSyncers_test.go b/update/container/trieSyncers_test.go new file mode 100644 index 0000000000..f1d8a8baf9 --- /dev/null +++ b/update/container/trieSyncers_test.go @@ -0,0 +1,103 @@ +package containers + +import ( + "context" + "errors" + "testing" + + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/update" + "github.com/ElrondNetwork/elrond-go/update/mock" + "github.com/stretchr/testify/require" +) + +func TestNewTrieSyncersContainer(t *testing.T) { + t.Parallel() + + tsc := NewTrieSyncersContainer() + require.False(t, check.IfNil(tsc)) +} + +func TestTrieSyncers_AddGetShouldWork(t *testing.T) { + t.Parallel() + + tsc := NewTrieSyncersContainer() + testKey := "key" + testVal := &mock.TrieSyncersStub{} + err := tsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := tsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) +} + +func TestTrieSyncers_AddMultipleShouldWork(t *testing.T) { + t.Parallel() + + tsc := NewTrieSyncersContainer() + testKey0 := "key0" + testVal0 := &mock.TrieSyncersStub{} + testKey1 := "key1" + testVal1 := &mock.TrieSyncersStub{} + + err := tsc.AddMultiple([]string{testKey0, testKey1}, []update.TrieSyncer{testVal0, testVal1}) + require.NoError(t, err) + + res0, err := tsc.Get(testKey0) + require.NoError(t, err) + require.Equal(t, testVal0, res0) + + res1, err := tsc.Get(testKey1) + require.NoError(t, err) + require.Equal(t, testVal1, res1) + + require.Equal(t, 2, tsc.Len()) +} + +func TestTrieSyncers_ReplaceShouldWork(t *testing.T) { + t.Parallel() + + tsc := NewTrieSyncersContainer() + testKey := "key" + testVal := &mock.TrieSyncersStub{} + err := tsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := tsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) + + // update + newTestVal := &mock.TrieSyncersStub{ + StartSyncingCalled: func(_ []byte, _ context.Context) error { + return errors.New("local err") + }, + } + err = tsc.Replace(testKey, newTestVal) + require.NoError(t, err) + + res, err = tsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, newTestVal, res) +} + +func TestTrieSyncers_DeleteShouldWork(t *testing.T) { + t.Parallel() + + tsc := NewTrieSyncersContainer() + testKey := "key" + testVal := &mock.TrieSyncersStub{} + err := tsc.Add(testKey, testVal) + require.NoError(t, err) + + res, err := tsc.Get(testKey) + require.NoError(t, err) + require.Equal(t, testVal, res) + + tsc.Remove(testKey) + + res, err = tsc.Get(testKey) + require.Nil(t, res) + require.Equal(t, update.ErrInvalidContainerKey, err) +} diff --git a/update/sync/base_test.go b/update/sync/base_test.go new file mode 100644 index 0000000000..0b40063ca9 --- /dev/null +++ b/update/sync/base_test.go @@ -0,0 +1,67 @@ +package sync + +import ( + "errors" + "testing" + "time" + + "github.com/ElrondNetwork/elrond-go/update" + "github.com/ElrondNetwork/elrond-go/update/mock" + "github.com/stretchr/testify/require" +) + +func TestGetDataFromStorage_NilStorageShouldErr(t *testing.T) { + t.Parallel() + + res, err := GetDataFromStorage([]byte("test"), nil) + require.Equal(t, update.ErrNilStorage, err) + require.Nil(t, res) +} + +func TestGetDataFromStorage_NotFoundShouldErr(t *testing.T) { + t.Parallel() + + localErr := errors.New("not found") + storer := &mock.StorerStub{ + GetCalled: func(_ []byte) ([]byte, error) { + return nil, localErr + }, + } + res, err := GetDataFromStorage([]byte("test"), storer) + require.Equal(t, localErr, err) + require.Nil(t, res) +} + +func TestGetDataFromStorage_FoundShouldWork(t *testing.T) { + t.Parallel() + + expRes := []byte("result") + storer := &mock.StorerStub{ + GetCalled: func(_ []byte) ([]byte, error) { + return expRes, nil + }, + } + res, err := GetDataFromStorage([]byte("test"), storer) + require.NoError(t, err) + require.Equal(t, expRes, res) +} + +func TestWaitFor_ShouldTimeout(t *testing.T) { + t.Parallel() + + chanToUse := make(chan bool, 1) + err := WaitFor(chanToUse, 10*time.Millisecond) + require.Equal(t, update.ErrTimeIsOut, err) +} + +func TestWaitFor_ShouldWorkAfterTheChannelIsWrittenIn(t *testing.T) { + t.Parallel() + + chanToUse := make(chan bool, 1) + go func() { + time.Sleep(10 * time.Millisecond) + chanToUse <- true + }() + err := WaitFor(chanToUse, 100*time.Millisecond) + require.NoError(t, err) +} diff --git a/update/sync/concurrentTriesMap_test.go b/update/sync/concurrentTriesMap_test.go new file mode 100644 index 0000000000..9340581bd6 --- /dev/null +++ b/update/sync/concurrentTriesMap_test.go @@ -0,0 +1,61 @@ +package sync + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/ElrondNetwork/elrond-go/core/random" + "github.com/ElrondNetwork/elrond-go/update/mock" + "github.com/stretchr/testify/require" +) + +func TestNewConcurrentTriesMap(t *testing.T) { + t.Parallel() + + ctm := newConcurrentTriesMap() + require.NotNil(t, ctm) +} + +func TestConcurrentTriesMap_ConcurrentAccesses(t *testing.T) { + t.Parallel() + + // when running with -race, this should not throw race conditions. If we remove the mutex protection inside the struct, + // this test will fail + testDuration := 50 * time.Millisecond + rnd := random.ConcurrentSafeIntRandomizer{} + ctx, cancel := context.WithTimeout(context.Background(), testDuration) + ctm := newConcurrentTriesMap() + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + default: + randomID := rnd.Intn(100) + ctm.setTrie(fmt.Sprintf("%d", randomID), &mock.TrieStub{}) + } + } + }(ctx) + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + default: + randomID := rnd.Intn(100) + ctm.getTrie(fmt.Sprintf("%d", randomID)) + } + } + }(ctx) + go func(ctx context.Context) { + for { + select { + case <-ctx.Done(): + default: + _ = ctm.getTries() + } + } + }(ctx) + time.Sleep(testDuration) + cancel() +} diff --git a/update/sync/syncHeadersByHash.go b/update/sync/syncHeadersByHash.go index de7db584b1..7f99f74069 100644 --- a/update/sync/syncHeadersByHash.go +++ b/update/sync/syncHeadersByHash.go @@ -176,7 +176,7 @@ func (m *syncHeadersByHash) getHeaderFromPoolOrStorage(hash []byte) (data.Header } var hdr block.Header - err = m.marshalizer.Unmarshal(hdr, hdrData) + err = m.marshalizer.Unmarshal(&hdr, hdrData) if err != nil { return nil, false } diff --git a/update/sync/syncHeadersByHash_test.go b/update/sync/syncHeadersByHash_test.go new file mode 100644 index 0000000000..a01a95ff96 --- /dev/null +++ b/update/sync/syncHeadersByHash_test.go @@ -0,0 +1,179 @@ +package sync + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/data" + "github.com/ElrondNetwork/elrond-go/data/block" + "github.com/ElrondNetwork/elrond-go/dataRetriever" + "github.com/ElrondNetwork/elrond-go/update" + "github.com/ElrondNetwork/elrond-go/update/mock" + "github.com/stretchr/testify/require" +) + +func TestNewMissingheadersByHashSyncer_NilParamsShouldErr(t *testing.T) { + t.Parallel() + + okArgs := getMisingHeadersByHashSyncerArgs() + + testInput := make(map[ArgsNewMissingHeadersByHashSyncer]error) + + nilStorerArgs := okArgs + nilStorerArgs.Storage = nil + testInput[nilStorerArgs] = dataRetriever.ErrNilHeadersStorage + + nilCacheArgs := okArgs + nilCacheArgs.Cache = nil + testInput[nilCacheArgs] = update.ErrNilCacher + + nilMarshalizerArgs := okArgs + nilMarshalizerArgs.Marshalizer = nil + testInput[nilMarshalizerArgs] = dataRetriever.ErrNilMarshalizer + + nilRequestHandlerArgs := okArgs + nilRequestHandlerArgs.RequestHandler = nil + testInput[nilRequestHandlerArgs] = update.ErrNilRequestHandler + + for args, expectedErr := range testInput { + mhhs, err := NewMissingheadersByHashSyncer(args) + require.True(t, check.IfNil(mhhs)) + require.Equal(t, expectedErr, err) + } +} + +func TestNewMissingheadersByHashSyncer_OkValsShouldWork(t *testing.T) { + t.Parallel() + + args := getMisingHeadersByHashSyncerArgs() + mhhs, err := NewMissingheadersByHashSyncer(args) + require.NoError(t, err) + require.NotNil(t, mhhs) +} + +func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInCacheShouldWork(t *testing.T) { + t.Parallel() + + args := getMisingHeadersByHashSyncerArgs() + args.Cache = &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(_ []byte) (data.HeaderHandler, error) { + return &block.MetaBlock{Nonce: 37}, nil + }, + } + mhhs, _ := NewMissingheadersByHashSyncer(args) + + err := mhhs.SyncMissingHeadersByHash([]uint32{0, 1}, [][]byte{[]byte("hash234")}, context.Background()) + require.NoError(t, err) +} + +func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInStorageShouldWork(t *testing.T) { + t.Parallel() + + args := getMisingHeadersByHashSyncerArgs() + args.Cache = &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(_ []byte) (data.HeaderHandler, error) { + return nil, errors.New("not found") + }, + } + args.Storage = &mock.StorerStub{ + GetCalled: func(key []byte) ([]byte, error) { + mb := &block.MetaBlock{Nonce: 37} + mbBytes, _ := args.Marshalizer.Marshal(mb) + return mbBytes, nil + }, + } + mhhs, _ := NewMissingheadersByHashSyncer(args) + + err := mhhs.SyncMissingHeadersByHash([]uint32{0, 1}, [][]byte{[]byte("hash234")}, context.Background()) + require.NoError(t, err) +} + +func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderNotFoundShouldTimeout(t *testing.T) { + t.Parallel() + + var errNotFound = errors.New("not found") + args := getMisingHeadersByHashSyncerArgs() + args.Cache = &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(_ []byte) (data.HeaderHandler, error) { + return nil, errNotFound + }, + } + args.Storage = &mock.StorerStub{ + GetCalled: func(_ []byte) ([]byte, error) { + return nil, errNotFound + }, + } + mhhs, _ := NewMissingheadersByHashSyncer(args) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) + err := mhhs.SyncMissingHeadersByHash([]uint32{0, 1}, [][]byte{[]byte("hash234")}, ctx) + cancel() + + require.Equal(t, update.ErrTimeIsOut, err) +} + +func TestSyncHeadersByHash_GetHeaders_NotSyncedShouldErr(t *testing.T) { + t.Parallel() + + args := getMisingHeadersByHashSyncerArgs() + mhhs, _ := NewMissingheadersByHashSyncer(args) + require.NotNil(t, mhhs) + + res, err := mhhs.GetHeaders() + require.Nil(t, res) + require.Equal(t, update.ErrNotSynced, err) +} + +func TestSyncHeadersByHash_GetHeaders_ShouldReceiveAndReturnOkMb(t *testing.T) { + t.Parallel() + + var handlerToNotify func(header data.HeaderHandler, shardHeaderHash []byte) + var errNotFound = errors.New("not found") + args := getMisingHeadersByHashSyncerArgs() + args.Storage = &mock.StorerStub{ + GetCalled: func(_ []byte) ([]byte, error) { + return nil, errNotFound + }, + } + args.Cache = &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(_ []byte) (data.HeaderHandler, error) { + return nil, errNotFound + }, + RegisterHandlerCalled: func(handler func(header data.HeaderHandler, shardHeaderHash []byte)) { + handlerToNotify = handler + }, + } + mhhs, _ := NewMissingheadersByHashSyncer(args) + require.NotNil(t, mhhs) + + expectedHash := []byte("hash") + expectedMB := &block.MetaBlock{Nonce: 37} + go func() { + time.Sleep(10 * time.Millisecond) + handlerToNotify(expectedMB, expectedHash) + }() + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + err := mhhs.SyncMissingHeadersByHash([]uint32{0}, [][]byte{[]byte("hash")}, ctx) + require.NoError(t, err) + cancel() + + res, err := mhhs.GetHeaders() + require.NoError(t, err) + require.NotNil(t, res) + + actualMb, ok := res[string(expectedHash)] + require.True(t, ok) + require.Equal(t, expectedMB, actualMb) +} + +func getMisingHeadersByHashSyncerArgs() ArgsNewMissingHeadersByHashSyncer { + return ArgsNewMissingHeadersByHashSyncer{ + Storage: &mock.StorerMock{}, + Cache: &mock.HeadersCacherStub{}, + Marshalizer: &mock.MarshalizerMock{}, + RequestHandler: &mock.RequestHandlerStub{}, + } +} diff --git a/update/sync/syncMiniBlocks_test.go b/update/sync/syncMiniBlocks_test.go index 24dbe7e491..2d742db0e4 100644 --- a/update/sync/syncMiniBlocks_test.go +++ b/update/sync/syncMiniBlocks_test.go @@ -225,3 +225,109 @@ func TestSyncPendingMiniBlocksFromMeta_MiniBlocksInPoolReceive(t *testing.T) { cancel() require.Nil(t, err) } + +func TestSyncPendingMiniBlocksFromMeta_MiniBlocksInStorageReceive(t *testing.T) { + t.Parallel() + + mbHash := []byte("mbHash") + mb := &block.MiniBlock{} + marshalizer := &mock.MarshalizerMock{} + args := ArgsNewPendingMiniBlocksSyncer{ + Storage: &mock.StorerStub{ + GetCalled: func(key []byte) (bytes []byte, err error) { + mbBytes, _ := marshalizer.Marshal(mb) + return mbBytes, nil + }, + }, + Cache: &mock.CacherStub{ + RegisterHandlerCalled: func(_ func(_ []byte, _ interface{})) {}, + PeekCalled: func(key []byte) (interface{}, bool) { + return nil, false + }, + }, + Marshalizer: &mock.MarshalizerFake{}, + RequestHandler: &mock.RequestHandlerStub{}, + } + + pendingMiniBlocksSyncer, err := NewPendingMiniBlocksSyncer(args) + require.Nil(t, err) + + metaBlock := &block.MetaBlock{ + Nonce: 1, Epoch: 1, RootHash: []byte("metaRootHash"), + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + { + ShardID: 0, + RootHash: []byte("shardDataRootHash"), + PendingMiniBlockHeaders: []block.MiniBlockHeader{{Hash: mbHash}}, + FirstPendingMetaBlock: []byte("firstPending"), + }, + }, + }, + } + unFinished := make(map[string]*block.MetaBlock) + unFinished["firstPending"] = metaBlock + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + err = pendingMiniBlocksSyncer.SyncPendingMiniBlocksFromMeta(metaBlock, unFinished, ctx) + cancel() + require.Nil(t, err) +} + +func TestSyncPendingMiniBlocksFromMeta_GetMiniBlocksShouldWork(t *testing.T) { + t.Parallel() + + mbHash := []byte("mbHash") + mb := &block.MiniBlock{ + TxHashes: [][]byte{[]byte("txHash")}, + } + localErr := errors.New("not found") + marshalizer := &mock.MarshalizerMock{} + args := ArgsNewPendingMiniBlocksSyncer{ + Storage: &mock.StorerStub{ + GetCalled: func(key []byte) (bytes []byte, err error) { + mbBytes, _ := marshalizer.Marshal(mb) + return mbBytes, nil + }, + GetFromEpochCalled: func(key []byte, epoch uint32) (bytes []byte, err error) { + return nil, localErr + }, + }, + Cache: &mock.CacherStub{ + RegisterHandlerCalled: func(_ func(_ []byte, _ interface{})) {}, + PeekCalled: func(key []byte) (interface{}, bool) { + return nil, false + }, + }, + Marshalizer: &mock.MarshalizerFake{}, + RequestHandler: &mock.RequestHandlerStub{}, + } + + pendingMiniBlocksSyncer, err := NewPendingMiniBlocksSyncer(args) + require.Nil(t, err) + + metaBlock := &block.MetaBlock{ + Nonce: 1, Epoch: 1, RootHash: []byte("metaRootHash"), + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + { + ShardID: 0, + RootHash: []byte("shardDataRootHash"), + PendingMiniBlockHeaders: []block.MiniBlockHeader{{Hash: mbHash}}, + FirstPendingMetaBlock: []byte("firstPending"), + }, + }, + }, + } + unFinished := make(map[string]*block.MetaBlock) + unFinished["firstPending"] = metaBlock + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + err = pendingMiniBlocksSyncer.SyncPendingMiniBlocksFromMeta(metaBlock, unFinished, ctx) + cancel() + require.Nil(t, err) + + res, err := pendingMiniBlocksSyncer.GetMiniBlocks() + require.NoError(t, err) + require.Equal(t, mb, res[string(mbHash)]) +} From 4f500bca901a20344c919fabb5c79f32d136314a Mon Sep 17 00:00:00 2001 From: bogdan-rosianu Date: Tue, 12 May 2020 14:08:43 +0300 Subject: [PATCH 19/79] EN-6411: add untracked stub file --- .../mock/metaBlockInterceptorProcessorStub.go | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 epochStart/mock/metaBlockInterceptorProcessorStub.go diff --git a/epochStart/mock/metaBlockInterceptorProcessorStub.go b/epochStart/mock/metaBlockInterceptorProcessorStub.go new file mode 100644 index 0000000000..915d3332a5 --- /dev/null +++ b/epochStart/mock/metaBlockInterceptorProcessorStub.go @@ -0,0 +1,42 @@ +package mock + +import ( + "context" + + "github.com/ElrondNetwork/elrond-go/data/block" + "github.com/ElrondNetwork/elrond-go/p2p" + "github.com/ElrondNetwork/elrond-go/process" +) + +// MetaBlockInterceptorProcessorStub - +type MetaBlockInterceptorProcessorStub struct { + GetEpochStartMetaBlockCalled func() (*block.MetaBlock, error) +} + +// Validate - +func (m *MetaBlockInterceptorProcessorStub) Validate(data process.InterceptedData, fromConnectedPeer p2p.PeerID) error { + return nil +} + +// Save - +func (m *MetaBlockInterceptorProcessorStub) Save(data process.InterceptedData, fromConnectedPeer p2p.PeerID) error { + return nil +} + +// SignalEndOfProcessing - +func (m *MetaBlockInterceptorProcessorStub) SignalEndOfProcessing(data []process.InterceptedData) { +} + +// IsInterfaceNil - +func (m *MetaBlockInterceptorProcessorStub) IsInterfaceNil() bool { + return m == nil +} + +// GetEpochStartMetaBlock - +func (m *MetaBlockInterceptorProcessorStub) GetEpochStartMetaBlock(_ context.Context) (*block.MetaBlock, error) { + if m.GetEpochStartMetaBlockCalled != nil { + return m.GetEpochStartMetaBlockCalled() + } + + return &block.MetaBlock{}, nil +} From d966ebd14f2e00837dbbae7c01b26f479fc7f88e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 14:25:59 +0300 Subject: [PATCH 20/79] Extra tests / coverage. --- storage/txcache/disabledCache_test.go | 37 ++++++++++++++++ storage/txcache/txCache_test.go | 64 +++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 storage/txcache/disabledCache_test.go diff --git a/storage/txcache/disabledCache_test.go b/storage/txcache/disabledCache_test.go new file mode 100644 index 0000000000..0f571551a3 --- /dev/null +++ b/storage/txcache/disabledCache_test.go @@ -0,0 +1,37 @@ +package txcache + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDisabledCache_DoesNothing(t *testing.T) { + cache := NewDisabledCache() + + ok, added := cache.AddTx(nil) + require.False(t, ok) + require.False(t, added) + + tx, ok := cache.GetByTxHash([]byte{}) + require.Nil(t, tx) + require.False(t, ok) + + selection := cache.SelectTransactions(42, 42) + require.Equal(t, 0, len(selection)) + + err := cache.RemoveTxByHash([]byte{}) + require.Nil(t, err) + + count := cache.CountTx() + require.Equal(t, int64(0), count) + + length := cache.Len() + require.Equal(t, 0, length) + + require.NotPanics(t, func() { cache.ForEachTransaction(func(_ []byte, _ *WrappedTransaction) {}) }) + + cache.Clear() + evicted := cache.Put(nil, nil) + require.False(t, evicted) +} diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index 91522a9d57..d6d701c877 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -13,6 +13,70 @@ import ( "github.com/stretchr/testify/require" ) +func Test_NewTxCache(t *testing.T) { + config := CacheConfig{ + Name: "test", + NumChunksHint: 16, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, + } + + evictionConfig := CacheConfig{ + Name: "test", + NumChunksHint: 16, + NumBytesPerSenderThreshold: math.MaxUint32, + CountPerSenderThreshold: math.MaxUint32, + MinGasPriceMicroErd: 100, + EvictionEnabled: true, + NumBytesThreshold: math.MaxUint32, + CountThreshold: math.MaxUint32, + NumSendersToEvictInOneStep: 100, + } + + cache, err := NewTxCache(config) + require.Nil(t, err) + require.NotNil(t, cache) + + badConfig := config + badConfig.Name = "" + requireErrorOnNewTxCache(t, badConfig, "config.Name") + + badConfig = config + badConfig.NumChunksHint = 0 + requireErrorOnNewTxCache(t, badConfig, "config.NumChunksHint") + + badConfig = config + badConfig.NumBytesPerSenderThreshold = 0 + requireErrorOnNewTxCache(t, badConfig, "config.NumBytesPerSenderThreshold") + + badConfig = config + badConfig.CountPerSenderThreshold = 0 + requireErrorOnNewTxCache(t, badConfig, "config.CountPerSenderThreshold") + + badConfig = config + badConfig.MinGasPriceMicroErd = 0 + requireErrorOnNewTxCache(t, badConfig, "config.MinGasPriceMicroErd") + + badConfig = evictionConfig + badConfig.NumBytesThreshold = 0 + requireErrorOnNewTxCache(t, badConfig, "config.NumBytesThreshold") + + badConfig = evictionConfig + badConfig.CountThreshold = 0 + requireErrorOnNewTxCache(t, badConfig, "config.CountThreshold") + + badConfig = evictionConfig + badConfig.NumSendersToEvictInOneStep = 0 + requireErrorOnNewTxCache(t, badConfig, "config.NumSendersToEvictInOneStep") +} + +func requireErrorOnNewTxCache(t *testing.T, config CacheConfig, errMessage string) { + cache, err := NewTxCache(config) + require.Contains(t, err.Error(), errMessage) + require.Nil(t, cache) +} + func Test_AddTx(t *testing.T) { cache := newCacheToTest() From e3d0dd49ede027a2757c585c11b9ede3f5239826 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 14:48:51 +0300 Subject: [PATCH 21/79] Cover disabled cache. --- storage/txcache/disabledCache.go | 4 ---- storage/txcache/disabledCache_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/storage/txcache/disabledCache.go b/storage/txcache/disabledCache.go index a0a5ef6e7d..663f3392da 100644 --- a/storage/txcache/disabledCache.go +++ b/storage/txcache/disabledCache.go @@ -69,10 +69,6 @@ func (cache *DisabledCache) Put(key []byte, value interface{}) (evicted bool) { // Get - func (cache *DisabledCache) Get(key []byte) (value interface{}, ok bool) { - tx, ok := cache.GetByTxHash(key) - if ok { - return tx.Tx, true - } return nil, false } diff --git a/storage/txcache/disabledCache_test.go b/storage/txcache/disabledCache_test.go index 0f571551a3..ae749c0c02 100644 --- a/storage/txcache/disabledCache_test.go +++ b/storage/txcache/disabledCache_test.go @@ -32,6 +32,33 @@ func TestDisabledCache_DoesNothing(t *testing.T) { require.NotPanics(t, func() { cache.ForEachTransaction(func(_ []byte, _ *WrappedTransaction) {}) }) cache.Clear() + evicted := cache.Put(nil, nil) require.False(t, evicted) + + value, ok := cache.Get([]byte{}) + require.Nil(t, value) + require.False(t, ok) + + value, ok = cache.Peek([]byte{}) + require.Nil(t, value) + require.False(t, ok) + + has := cache.Has([]byte{}) + require.False(t, has) + + has, evicted = cache.HasOrAdd([]byte{}, nil) + require.False(t, has) + require.False(t, evicted) + + cache.Remove([]byte{}) + cache.RemoveOldest() + + keys := cache.Keys() + require.Equal(t, 0, len(keys)) + + maxSize := cache.MaxSize() + require.Equal(t, 0, maxSize) + + require.NotPanics(t, func() { cache.RegisterHandler(func(_ []byte, _ interface{}) {}) }) } From f4ffcabcf11392d1eadd03b258864c72ac21e066 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 15:12:30 +0300 Subject: [PATCH 22/79] Fix long test. --- integrationTests/testInitializer.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index 488d10a902..c5ce044bf8 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -8,6 +8,7 @@ import ( "encoding/hex" "fmt" "io/ioutil" + "math" "math/big" "strings" "sync" @@ -1914,9 +1915,9 @@ func createTxPool(selfShardID uint32) (dataRetriever.ShardedDataCacherNotifier, txpool.ArgShardedTxPool{ Config: storageUnit.CacheConfig{ Size: 100000, - SizePerSender: 1000, + SizePerSender: math.MaxUint32, SizeInBytes: 1000000000, - SizeInBytesPerSender: 10000000, + SizeInBytesPerSender: math.MaxUint32, Shards: 16, }, MinGasPrice: 100000000000000, From 588526cbeba3a00a5b83adeba8c5fb044ce3aa3f Mon Sep 17 00:00:00 2001 From: andrei-marinica Date: Tue, 12 May 2020 15:55:12 +0300 Subject: [PATCH 23/79] integrate Arwen v0.3.17 --- genesis/process/genesisBlockCreator_test.go | 2 +- go.mod | 4 +++- go.sum | 10 +--------- integrationTests/multiShard/hardFork/hardFork_test.go | 2 +- integrationTests/testProcessorNode.go | 2 +- integrationTests/vm/testInitializer.go | 2 +- process/factory/shard/vmContainerFactory_test.go | 4 ++-- 7 files changed, 10 insertions(+), 16 deletions(-) diff --git a/genesis/process/genesisBlockCreator_test.go b/genesis/process/genesisBlockCreator_test.go index e104711e87..1a7d2a74fc 100644 --- a/genesis/process/genesisBlockCreator_test.go +++ b/genesis/process/genesisBlockCreator_test.go @@ -61,7 +61,7 @@ func createMockArgument() ArgsGenesisBlockCreator { }, } - arg.GasMap = arwenConfig.MakeGasMap(1) + arg.GasMap = arwenConfig.MakeGasMapForTests() defaults.FillGasMapInternal(arg.GasMap, 1) ted := &economics.TestEconomicsData{ diff --git a/go.mod b/go.mod index fa52224d43..5abe95ad5d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ElrondNetwork/elrond-go go 1.13 require ( - github.com/ElrondNetwork/arwen-wasm-vm v0.3.16 + github.com/ElrondNetwork/arwen-wasm-vm v0.3.17 github.com/ElrondNetwork/concurrent-map v0.1.2 github.com/ElrondNetwork/elrond-go-logger v1.0.3 github.com/ElrondNetwork/elrond-vm v0.0.25 @@ -47,3 +47,5 @@ require ( golang.org/x/net v0.0.0-20190620200207-3b0461eec859 gopkg.in/go-playground/validator.v8 v8.18.2 ) + +replace github.com/ElrondNetwork/arwen-wasm-vm => ../arwen-wasm-vm diff --git a/go.sum b/go.sum index 62387ac386..fb133aaa92 100644 --- a/go.sum +++ b/go.sum @@ -3,10 +3,6 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.15 h1:tmkfiTbOpmNZrjoYGq5ESfmg/DblUBuS0GvzP5Zoums= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.15/go.mod h1:dVwR0ZGVOlr7BH9YbacSBWQ3CSASSp5BQU1tTiD/dOA= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.16 h1:JZurmIDNlKK3W8kCClQ1DNAl7j4sLfGgc9yniVjisGE= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.16/go.mod h1:Ny/uDh27JLWdFaCTp+Ek4hw5Ory/sTsjA3QWmP//mpU= github.com/ElrondNetwork/big-int-util v0.0.5 h1:e/9kK++9ZH/SdIYqLSUPRFYrDZmDWDgff3/7SCydq5I= github.com/ElrondNetwork/big-int-util v0.0.5/go.mod h1:96viBvoTXLjZOhEvE0D+QnAwg1IJLPAK6GVHMbC7Aw4= github.com/ElrondNetwork/concurrent-map v0.1.2 h1:mr2sVF2IPDsJO8DNGzCUiNQOJcadHuIRVZn+QFnCBlE= @@ -19,14 +15,10 @@ github.com/ElrondNetwork/elrond-vm v0.0.25 h1:FIALKEneTS6BsGgdKDUx16w81S1MvwYnLc github.com/ElrondNetwork/elrond-vm v0.0.25/go.mod h1:w0jMH4xA506twG5Gkki5MN54eQ0jPCg06XuHvCQg44g= github.com/ElrondNetwork/elrond-vm-common v0.0.0-20191203115206-691b00a6e76a/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= github.com/ElrondNetwork/elrond-vm-common v0.1.9/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= -github.com/ElrondNetwork/elrond-vm-common v0.1.17/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= -github.com/ElrondNetwork/elrond-vm-common v0.1.18 h1:lgWO37mySU3OlrsMZSPpHcWDzwFBiAik4Q8LkFztlH0= -github.com/ElrondNetwork/elrond-vm-common v0.1.18/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= github.com/ElrondNetwork/elrond-vm-common v0.1.19 h1:mRO768HtMyXY23pvG18DonKVEIlNvXxoyKP94S9fb2A= github.com/ElrondNetwork/elrond-vm-common v0.1.19/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= github.com/ElrondNetwork/elrond-vm-util v0.1.1/go.mod h1:02LPKFh/Z5rbejgW2dazwjWGnsniuLOhRM2JjaOA3Mg= -github.com/ElrondNetwork/elrond-vm-util v0.1.8/go.mod h1:nj0ZN4uEKCbpxqUOaAgWtbpGmkm17e0sRfc6T1TVo7w= -github.com/ElrondNetwork/elrond-vm-util v0.2.3/go.mod h1:tLiuKpnQB5IrcMtZvwAJqo2WwUMzXX024SsEsTlmNL4= +github.com/ElrondNetwork/elrond-vm-util v0.2.5/go.mod h1:tLiuKpnQB5IrcMtZvwAJqo2WwUMzXX024SsEsTlmNL4= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= diff --git a/integrationTests/multiShard/hardFork/hardFork_test.go b/integrationTests/multiShard/hardFork/hardFork_test.go index a95b5ae866..78fb148b56 100644 --- a/integrationTests/multiShard/hardFork/hardFork_test.go +++ b/integrationTests/multiShard/hardFork/hardFork_test.go @@ -213,7 +213,7 @@ func hardForkImport( importStorageConfigs []*config.StorageConfig, ) { for id, node := range nodes { - gasSchedule := arwenConfig.MakeGasMap(1) + gasSchedule := arwenConfig.MakeGasMapForTests() defaults.FillGasMapInternal(gasSchedule, 1) log.Warn("started import process") diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index b6db018b05..04416e0ddd 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -832,7 +832,7 @@ func (tpn *TestProcessorNode) initInnerProcessors() { tpn.ShardCoordinator, ) - gasSchedule := arwenConfig.MakeGasMap(1) + gasSchedule := arwenConfig.MakeGasMapForTests() defaults.FillGasMapInternal(gasSchedule, 1) argsBuiltIn := builtInFunctions.ArgsCreateBuiltInFunctionContainer{ GasMap: gasSchedule, diff --git a/integrationTests/vm/testInitializer.go b/integrationTests/vm/testInitializer.go index 90394f8c1f..de7be040cc 100644 --- a/integrationTests/vm/testInitializer.go +++ b/integrationTests/vm/testInitializer.go @@ -256,7 +256,7 @@ func CreateVMAndBlockchainHook( ) (process.VirtualMachinesContainer, *hooks.BlockChainHookImpl) { actualGasSchedule := gasSchedule if gasSchedule == nil { - actualGasSchedule = arwenConfig.MakeGasMap(1) + actualGasSchedule = arwenConfig.MakeGasMapForTests() defaults.FillGasMapInternal(actualGasSchedule, 1) } diff --git a/process/factory/shard/vmContainerFactory_test.go b/process/factory/shard/vmContainerFactory_test.go index fda81785a0..2e242192ec 100644 --- a/process/factory/shard/vmContainerFactory_test.go +++ b/process/factory/shard/vmContainerFactory_test.go @@ -53,7 +53,7 @@ func TestNewVMContainerFactory_OkValues(t *testing.T) { vmf, err := NewVMContainerFactory( config.VirtualMachineConfig{}, 10000, - arwenConfig.MakeGasMap(1), + arwenConfig.MakeGasMapForTests(), createMockVMAccountsArguments(), ) @@ -68,7 +68,7 @@ func TestVmContainerFactory_Create(t *testing.T) { vmf, err := NewVMContainerFactory( config.VirtualMachineConfig{}, 10000, - arwenConfig.MakeGasMap(1), + arwenConfig.MakeGasMapForTests(), createMockVMAccountsArguments(), ) assert.NotNil(t, vmf) From 6c3a4039aeadd3e029c6a29a6ca9b99f8a2db719 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 17:26:07 +0300 Subject: [PATCH 24/79] Add extra tests. --- storage/txcache/eviction_test.go | 2 +- storage/txcache/sweeping_test.go | 6 +- storage/txcache/testutils_test.go | 30 +++++++++ storage/txcache/txCache_test.go | 87 ++++++++++++++++++++----- storage/txcache/txListForSender_test.go | 4 +- 5 files changed, 106 insertions(+), 23 deletions(-) diff --git a/storage/txcache/eviction_test.go b/storage/txcache/eviction_test.go index 57366378b9..fb08dfc434 100644 --- a/storage/txcache/eviction_test.go +++ b/storage/txcache/eviction_test.go @@ -257,7 +257,7 @@ func Test_AddWithEviction_UniformDistribution_25000x10(t *testing.T) { } func Test_EvictSendersAndTheirTxs_Concurrently(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() var wg sync.WaitGroup for i := 0; i < 10; i++ { diff --git a/storage/txcache/sweeping_test.go b/storage/txcache/sweeping_test.go index 2d4a9f5d6f..9e5e563952 100644 --- a/storage/txcache/sweeping_test.go +++ b/storage/txcache/sweeping_test.go @@ -7,7 +7,7 @@ import ( ) func TestSweeping_CollectSweepable(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("alice-42"), "alice", 42)) cache.AddTx(createTx([]byte("bob-42"), "bob", 42)) @@ -50,7 +50,7 @@ func TestSweeping_CollectSweepable(t *testing.T) { } func TestSweeping_WhenSendersEscapeCollection(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("alice-42"), "alice", 42)) cache.AddTx(createTx([]byte("bob-42"), "bob", 42)) @@ -95,7 +95,7 @@ func TestSweeping_WhenSendersEscapeCollection(t *testing.T) { } func TestSweeping_SweepSweepable(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("alice-42"), "alice", 42)) cache.AddTx(createTx([]byte("bob-42"), "bob", 42)) diff --git a/storage/txcache/testutils_test.go b/storage/txcache/testutils_test.go index 46a4d56635..9b9ee67379 100644 --- a/storage/txcache/testutils_test.go +++ b/storage/txcache/testutils_test.go @@ -22,6 +22,36 @@ func kBToBytes(kB float32) uint64 { return uint64(kB * 1000) } +func (cache *TxCache) areInternalMapsConsistent() bool { + internalMapByHash := cache.txByHash + internalMapBySender := cache.txListBySender + + senders := internalMapBySender.getSnapshotAscending() + numTransactionsByHash := len(internalMapByHash.keys()) + numTransactionsBySender := 0 + + for _, sender := range senders { + numTransactionsBySender += int(sender.countTx()) + + for _, hash := range sender.getTxHashesAsStrings() { + _, ok := internalMapByHash.getTx(hash) + if !ok { + return false + } + } + } + + if numTransactionsBySender != numTransactionsByHash { + return false + } + + return true +} + +func (cache *TxCache) getHashesForSender(sender string) []string { + return cache.getListForSender(sender).getTxHashesAsStrings() +} + func (cache *TxCache) getListForSender(sender string) *txListForSender { return cache.txListBySender.testGetListForSender(sender) } diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index d6d701c877..6d428a5f13 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -78,7 +78,7 @@ func requireErrorOnNewTxCache(t *testing.T, config CacheConfig, errMessage strin } func Test_AddTx(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() tx := createTx([]byte("hash-1"), "alice", 1) @@ -97,7 +97,7 @@ func Test_AddTx(t *testing.T) { } func Test_AddNilTx_DoesNothing(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() txHash := []byte("hash-1") @@ -110,8 +110,46 @@ func Test_AddNilTx_DoesNothing(t *testing.T) { require.Nil(t, foundTx) } +func Test_AddTx_AppliesSizeConstraintsPerSender_NumTransactions(t *testing.T) { + cache := newCacheToTest(math.MaxUint32, 3) + + cache.AddTx(createTx([]byte("tx-alice-1"), "alice", 1)) + cache.AddTx(createTx([]byte("tx-alice-2"), "alice", 2)) + cache.AddTx(createTx([]byte("tx-alice-4"), "alice", 4)) + cache.AddTx(createTx([]byte("tx-bob-1"), "bob", 1)) + cache.AddTx(createTx([]byte("tx-bob-2"), "bob", 2)) + require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) + require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.True(t, cache.areInternalMapsConsistent()) + + cache.AddTx(createTx([]byte("tx-alice-3"), "alice", 3)) + require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) + require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.True(t, cache.areInternalMapsConsistent()) +} + +func Test_AddTx_AppliesSizeConstraintsPerSender_NumBytes(t *testing.T) { + cache := newCacheToTest(1024, math.MaxUint32) + + cache.AddTx(createTxWithParams([]byte("tx-alice-1"), "alice", 1, 128, 42, 42)) + cache.AddTx(createTxWithParams([]byte("tx-alice-2"), "alice", 2, 512, 42, 42)) + cache.AddTx(createTxWithParams([]byte("tx-alice-4"), "alice", 3, 256, 42, 42)) + cache.AddTx(createTxWithParams([]byte("tx-bob-1"), "bob", 1, 512, 42, 42)) + cache.AddTx(createTxWithParams([]byte("tx-bob-2"), "bob", 2, 513, 42, 42)) + + require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) + require.ElementsMatch(t, []string{"tx-bob-1"}, cache.getHashesForSender("bob")) + require.True(t, cache.areInternalMapsConsistent()) + + cache.AddTx(createTxWithParams([]byte("tx-alice-3"), "alice", 3, 256, 42, 42)) + cache.AddTx(createTxWithParams([]byte("tx-bob-2"), "bob", 3, 512, 42, 42)) + require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) + require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.True(t, cache.areInternalMapsConsistent()) +} + func Test_RemoveByTxHash(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-1"), "alice", 1)) cache.AddTx(createTx([]byte("hash-2"), "alice", 2)) @@ -130,7 +168,7 @@ func Test_RemoveByTxHash(t *testing.T) { } func Test_CountTx_And_Len(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-1"), "alice", 1)) cache.AddTx(createTx([]byte("hash-2"), "alice", 2)) @@ -141,7 +179,7 @@ func Test_CountTx_And_Len(t *testing.T) { } func Test_GetByTxHash_And_Peek_And_Get(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() txHash := []byte("hash-1") tx := createTx(txHash, "alice", 1) @@ -169,13 +207,13 @@ func Test_GetByTxHash_And_Peek_And_Get(t *testing.T) { } func Test_RemoveByTxHash_Error_WhenMissing(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() err := cache.RemoveTxByHash([]byte("missing")) require.Equal(t, err, errTxNotFound) } func Test_RemoveByTxHash_Error_WhenMapsInconsistency(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() txHash := []byte("hash-1") tx := createTx(txHash, "alice", 1) @@ -189,7 +227,7 @@ func Test_RemoveByTxHash_Error_WhenMapsInconsistency(t *testing.T) { } func Test_Clear(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-alice-1"), "alice", 1)) cache.AddTx(createTx([]byte("hash-bob-7"), "bob", 7)) @@ -201,7 +239,7 @@ func Test_Clear(t *testing.T) { } func Test_ForEachTransaction(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-alice-1"), "alice", 1)) cache.AddTx(createTx([]byte("hash-bob-7"), "bob", 7)) @@ -214,7 +252,7 @@ func Test_ForEachTransaction(t *testing.T) { } func Test_SelectTransactions_Dummy(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-alice-4"), "alice", 4)) cache.AddTx(createTx([]byte("hash-alice-3"), "alice", 3)) @@ -230,7 +268,7 @@ func Test_SelectTransactions_Dummy(t *testing.T) { } func Test_SelectTransactions_BreaksAtNonceGaps(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("hash-alice-1"), "alice", 1)) cache.AddTx(createTx([]byte("hash-alice-2"), "alice", 2)) @@ -251,7 +289,7 @@ func Test_SelectTransactions_BreaksAtNonceGaps(t *testing.T) { } func Test_SelectTransactions(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() // Add "nSenders" * "nTransactionsPerSender" transactions in the cache (in reversed nonce order) nSenders := 1000 @@ -288,7 +326,7 @@ func Test_SelectTransactions(t *testing.T) { } func Test_Keys(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() cache.AddTx(createTx([]byte("alice-x"), "alice", 42)) cache.AddTx(createTx([]byte("alice-y"), "alice", 43)) @@ -346,7 +384,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { } func Test_NotImplementedFunctions(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() evicted := cache.Put(nil, nil) require.False(t, evicted) @@ -364,7 +402,7 @@ func Test_NotImplementedFunctions(t *testing.T) { } func Test_IsInterfaceNil(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() require.False(t, check.IfNil(cache)) makeNil := func() storage.Cacher { @@ -376,7 +414,7 @@ func Test_IsInterfaceNil(t *testing.T) { } func TestTxCache_ConcurrentMutationAndSelection(t *testing.T) { - cache := newCacheToTest() + cache := newUnconstrainedCacheToTest() // Alice will quickly move between two score buckets (chunks) cheapTransaction := createTxWithParams([]byte("alice-x-o"), "alice", 0, 128, 50000, 100*oneTrilion) @@ -413,7 +451,7 @@ func TestTxCache_ConcurrentMutationAndSelection(t *testing.T) { require.False(t, timedOut, "Timed out. Perhaps deadlock?") } -func newCacheToTest() *TxCache { +func newUnconstrainedCacheToTest() *TxCache { cache, err := NewTxCache(CacheConfig{ Name: "test", NumChunksHint: 16, @@ -421,6 +459,21 @@ func newCacheToTest() *TxCache { CountPerSenderThreshold: math.MaxUint32, MinGasPriceMicroErd: 100, }) + if err != nil { + panic(fmt.Sprintf("newUnconstrainedCacheToTest(): %s", err)) + } + + return cache +} + +func newCacheToTest(numBytesPerSenderThreshold uint32, countPerSenderThreshold uint32) *TxCache { + cache, err := NewTxCache(CacheConfig{ + Name: "test", + NumChunksHint: 16, + NumBytesPerSenderThreshold: numBytesPerSenderThreshold, + CountPerSenderThreshold: countPerSenderThreshold, + MinGasPriceMicroErd: 100, + }) if err != nil { panic(fmt.Sprintf("newCacheToTest(): %s", err)) } diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index fac3ac8712..30d1055267 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -43,7 +43,7 @@ func TestListForSender_AddTx_IgnoresDuplicates(t *testing.T) { require.False(t, added) } -func TestListForSender_AddTx_AppliesSizeConstraints_Count(t *testing.T) { +func TestListForSender_AddTx_AppliesSizeConstraints_NumTransactions(t *testing.T) { list := newListToTest(math.MaxUint32, 3) list.AddTx(createTx([]byte("tx1"), ".", 1)) @@ -67,7 +67,7 @@ func TestListForSender_AddTx_AppliesSizeConstraints_Count(t *testing.T) { require.ElementsMatch(t, []string{"tx3++"}, hashesAsStrings(evicted)) } -func TestListForSender_AddTx_AppliesSizeConstraints_SizeInBytes(t *testing.T) { +func TestListForSender_AddTx_AppliesSizeConstraints_NumBytes(t *testing.T) { list := newListToTest(1024, math.MaxUint32) list.AddTx(createTxWithParams([]byte("tx1"), ".", 1, 128, 42, 42)) From 636ad8b0a402a32601b81e5d01059d07f90d13bd Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 18:53:37 +0300 Subject: [PATCH 25/79] Adjust order of magnitude for gas price. --- dataRetriever/factory/txpool/txPoolFactory_test.go | 6 +++--- dataRetriever/txpool/shardedTxPool.go | 6 +++--- dataRetriever/txpool/shardedTxPool_test.go | 12 ++++++------ epochStart/metachain/epochStartData_test.go | 2 +- genesis/mock/poolsHolderMock.go | 2 +- integrationTests/consensus/testInitializer.go | 2 +- integrationTests/testInitializer.go | 2 +- process/block/preprocess/transactions_test.go | 2 +- process/block/shardblock_test.go | 2 +- process/coordinator/process_test.go | 2 +- process/mock/poolsHolderMock.go | 2 +- update/mock/poolsHolderMock.go | 2 +- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/dataRetriever/factory/txpool/txPoolFactory_test.go b/dataRetriever/factory/txpool/txPoolFactory_test.go index 5cd85f4c65..dd7c192820 100644 --- a/dataRetriever/factory/txpool/txPoolFactory_test.go +++ b/dataRetriever/factory/txpool/txPoolFactory_test.go @@ -10,14 +10,14 @@ import ( func Test_CreateNewTxPool_ShardedData(t *testing.T) { config := storageUnit.CacheConfig{Type: storageUnit.FIFOShardedCache, Size: 100, SizeInBytes: 40960, Shards: 1} - args := txpool.ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 1} + args := txpool.ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 1} txPool, err := CreateTxPool(args) require.Nil(t, err) require.NotNil(t, txPool) config = storageUnit.CacheConfig{Type: storageUnit.LRUCache, Size: 100, SizeInBytes: 40960, Shards: 1} - args = txpool.ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 1} + args = txpool.ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 1} txPool, err = CreateTxPool(args) require.Nil(t, err) require.NotNil(t, txPool) @@ -25,7 +25,7 @@ func Test_CreateNewTxPool_ShardedData(t *testing.T) { func Test_CreateNewTxPool_ShardedTxPool(t *testing.T) { config := storageUnit.CacheConfig{Size: 100, SizePerSender: 1, SizeInBytes: 40960, SizeInBytesPerSender: 40960, Shards: 1} - args := txpool.ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 1} + args := txpool.ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 1} txPool, err := CreateTxPool(args) require.Nil(t, err) diff --git a/dataRetriever/txpool/shardedTxPool.go b/dataRetriever/txpool/shardedTxPool.go index 66a966cb52..5e8b7d7ee1 100644 --- a/dataRetriever/txpool/shardedTxPool.go +++ b/dataRetriever/txpool/shardedTxPool.go @@ -37,14 +37,14 @@ type txPoolShard struct { // NewShardedTxPool creates a new sharded tx pool // Implements "dataRetriever.TxPool" func NewShardedTxPool(args ArgShardedTxPool) (dataRetriever.ShardedDataCacherNotifier, error) { - log.Trace("NewShardedTxPool", "args", args) + log.Info("NewShardedTxPool", "args", args) err := args.verify() if err != nil { return nil, err } - const oneTrilion = 1000000 * 1000000 + const oneBillion = 1000000 * 1000 numCaches := 2*args.NumberOfShards - 1 cacheConfigPrototype := txcache.CacheConfig{ @@ -55,7 +55,7 @@ func NewShardedTxPool(args ArgShardedTxPool) (dataRetriever.ShardedDataCacherNot CountThreshold: args.Config.Size / numCaches, CountPerSenderThreshold: args.Config.SizePerSender, NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, - MinGasPriceMicroErd: uint32(args.MinGasPrice / oneTrilion), + MinGasPriceMicroErd: uint32(args.MinGasPrice / oneBillion), } cacheConfigPrototypeForSelfShard := cacheConfigPrototype diff --git a/dataRetriever/txpool/shardedTxPool_test.go b/dataRetriever/txpool/shardedTxPool_test.go index 820451668e..6cfc3f4443 100644 --- a/dataRetriever/txpool/shardedTxPool_test.go +++ b/dataRetriever/txpool/shardedTxPool_test.go @@ -24,7 +24,7 @@ func Test_NewShardedTxPool(t *testing.T) { } func Test_NewShardedTxPool_WhenBadConfig(t *testing.T) { - goodArgs := ArgShardedTxPool{Config: storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16}, MinGasPrice: 100000000000000, NumberOfShards: 1} + goodArgs := ArgShardedTxPool{Config: storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16}, MinGasPrice: 200000000000, NumberOfShards: 1} args := goodArgs args.Config.SizeInBytes = 1 @@ -78,7 +78,7 @@ func Test_NewShardedTxPool_WhenBadConfig(t *testing.T) { func Test_NewShardedTxPool_ComputesCacheConfig(t *testing.T) { config := storageUnit.CacheConfig{SizeInBytes: 524288000, SizeInBytesPerSender: 614400, Size: 900000, SizePerSender: 1000, Shards: 1} - args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 5} + args := ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 5} poolAsInterface, err := NewShardedTxPool(args) require.Nil(t, err) @@ -91,7 +91,7 @@ func Test_NewShardedTxPool_ComputesCacheConfig(t *testing.T) { require.Equal(t, uint32(100000), pool.cacheConfigPrototype.CountThreshold) require.Equal(t, uint32(1000), pool.cacheConfigPrototype.CountPerSenderThreshold) require.Equal(t, uint32(100), pool.cacheConfigPrototype.NumSendersToEvictInOneStep) - require.Equal(t, uint32(100), pool.cacheConfigPrototype.MinGasPriceMicroErd) + require.Equal(t, uint32(200), pool.cacheConfigPrototype.MinGasPriceMicroErd) require.Equal(t, uint32(291271110), pool.cacheConfigPrototypeForSelfShard.NumBytesThreshold) require.Equal(t, uint32(500000), pool.cacheConfigPrototypeForSelfShard.CountThreshold) } @@ -319,7 +319,7 @@ func Test_NotImplementedFunctions(t *testing.T) { func Test_routeToCacheUnions(t *testing.T) { config := storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16} - args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 4, SelfShardID: 42} + args := ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 4, SelfShardID: 42} poolAsInterface, _ := NewShardedTxPool(args) pool := poolAsInterface.(*shardedTxPool) @@ -334,7 +334,7 @@ func Test_routeToCacheUnions(t *testing.T) { func Test_getCacheConfig(t *testing.T) { config := storageUnit.CacheConfig{Size: 150, SizePerSender: 1, SizeInBytes: 61440, SizeInBytesPerSender: 40960, Shards: 16} - args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 8, SelfShardID: 4} + args := ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 8, SelfShardID: 4} poolAsInterface, _ := NewShardedTxPool(args) pool := poolAsInterface.(*shardedTxPool) @@ -368,6 +368,6 @@ type thisIsNotATransaction struct { func newTxPoolToTest() (dataRetriever.ShardedDataCacherNotifier, error) { config := storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16} - args := ArgShardedTxPool{Config: config, MinGasPrice: 100000000000000, NumberOfShards: 4} + args := ArgShardedTxPool{Config: config, MinGasPrice: 200000000000, NumberOfShards: 4} return NewShardedTxPool(args) } diff --git a/epochStart/metachain/epochStartData_test.go b/epochStart/metachain/epochStartData_test.go index 5563c0fdaa..e18704570b 100644 --- a/epochStart/metachain/epochStartData_test.go +++ b/epochStart/metachain/epochStartData_test.go @@ -108,7 +108,7 @@ func createTxPool(selfShardID uint32) (dataRetriever.ShardedDataCacherNotifier, SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, SelfShardID: selfShardID, }, diff --git a/genesis/mock/poolsHolderMock.go b/genesis/mock/poolsHolderMock.go index 9bd448e8c1..40b22d2cfe 100644 --- a/genesis/mock/poolsHolderMock.go +++ b/genesis/mock/poolsHolderMock.go @@ -36,7 +36,7 @@ func NewPoolsHolderMock() *PoolsHolderMock { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/integrationTests/consensus/testInitializer.go b/integrationTests/consensus/testInitializer.go index e1249e03c5..470fcdbfca 100644 --- a/integrationTests/consensus/testInitializer.go +++ b/integrationTests/consensus/testInitializer.go @@ -170,7 +170,7 @@ func createTestShardDataPool() dataRetriever.PoolsHolder { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index c5ce044bf8..a6579eebe9 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -1920,7 +1920,7 @@ func createTxPool(selfShardID uint32) (dataRetriever.ShardedDataCacherNotifier, SizeInBytesPerSender: math.MaxUint32, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, SelfShardID: selfShardID, }, diff --git a/process/block/preprocess/transactions_test.go b/process/block/preprocess/transactions_test.go index 676bde4d61..517d8b9b0f 100644 --- a/process/block/preprocess/transactions_test.go +++ b/process/block/preprocess/transactions_test.go @@ -1063,7 +1063,7 @@ func createTxPool() (dataRetriever.ShardedDataCacherNotifier, error) { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/process/block/shardblock_test.go b/process/block/shardblock_test.go index 1bc6865282..98f57684d0 100644 --- a/process/block/shardblock_test.go +++ b/process/block/shardblock_test.go @@ -55,7 +55,7 @@ func createTestShardDataPool() dataRetriever.PoolsHolder { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/process/coordinator/process_test.go b/process/coordinator/process_test.go index 3c5368d005..245a7ee652 100644 --- a/process/coordinator/process_test.go +++ b/process/coordinator/process_test.go @@ -2547,7 +2547,7 @@ func createTxPool() (dataRetriever.ShardedDataCacherNotifier, error) { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/process/mock/poolsHolderMock.go b/process/mock/poolsHolderMock.go index 9bd448e8c1..40b22d2cfe 100644 --- a/process/mock/poolsHolderMock.go +++ b/process/mock/poolsHolderMock.go @@ -36,7 +36,7 @@ func NewPoolsHolderMock() *PoolsHolderMock { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) diff --git a/update/mock/poolsHolderMock.go b/update/mock/poolsHolderMock.go index 9d2680b65c..975f0fa948 100644 --- a/update/mock/poolsHolderMock.go +++ b/update/mock/poolsHolderMock.go @@ -35,7 +35,7 @@ func NewPoolsHolderMock() *PoolsHolderMock { SizeInBytesPerSender: 10000000, Shards: 16, }, - MinGasPrice: 100000000000000, + MinGasPrice: 200000000000, NumberOfShards: 1, }, ) From 704c37779694ef6fedc538d2e0982ce0adb56222 Mon Sep 17 00:00:00 2001 From: andrei-marinica Date: Tue, 12 May 2020 18:59:48 +0300 Subject: [PATCH 26/79] new delegation contract --- .../config/genesisContracts/delegation.wasm | Bin 37422 -> 52245 bytes .../testdata/delegate/delegation.wasm | Bin 37422 -> 52245 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/cmd/node/config/genesisContracts/delegation.wasm b/cmd/node/config/genesisContracts/delegation.wasm index bf8f22fc628f25f271f2582f4eb536a7546ea92f..51a41a0896eca8f95a086c1198c6d373750d15fd 100755 GIT binary patch literal 52245 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 HV+{O1ysfPT literal 37422 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 D!&)`; diff --git a/integrationTests/multiShard/smartContract/testdata/delegate/delegation.wasm b/integrationTests/multiShard/smartContract/testdata/delegate/delegation.wasm index bf8f22fc628f25f271f2582f4eb536a7546ea92f..51a41a0896eca8f95a086c1198c6d373750d15fd 100755 GIT binary patch literal 52245 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 HV+{O1ysfPT literal 37422 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 D!&)`; From e9e47396577a97b7f7ddc5a5b25aead5f4fdc896 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 19:51:27 +0300 Subject: [PATCH 27/79] Extra log. --- storage/txcache/txCache.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index 5628241a4a..88c8d9bd73 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -76,7 +76,11 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { cache.monitorTxAddition() } - cache.txByHash.RemoveTxsBulk(evicted) + if len(evicted) > 0 { + log.Trace("TxCache.AddTx()", "len(evicted)", len(evicted)) + cache.txByHash.RemoveTxsBulk(evicted) + } + return } From b3858ef49acbceecb5078476016f9c6a5e409aff Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 21:32:34 +0300 Subject: [PATCH 28/79] Fix ERD scale for score. --- dataRetriever/txpool/shardedTxPool.go | 2 +- dataRetriever/txpool/shardedTxPool_test.go | 2 +- storage/txcache/config.go | 6 ++-- storage/txcache/eviction_test.go | 30 +++++++++---------- storage/txcache/monitoring_test.go | 4 +-- storage/txcache/testutils_test.go | 6 ++-- storage/txcache/txCache_test.go | 20 ++++++------- .../txcache/txListForSenderAsSortedMapItem.go | 10 +++---- .../txListForSenderAsSortedMapItem_test.go | 22 +++++++------- storage/txcache/txListForSender_test.go | 4 +-- storage/txcache/txMeasures.go | 15 +++++----- 11 files changed, 60 insertions(+), 61 deletions(-) diff --git a/dataRetriever/txpool/shardedTxPool.go b/dataRetriever/txpool/shardedTxPool.go index 5e8b7d7ee1..5961b7f535 100644 --- a/dataRetriever/txpool/shardedTxPool.go +++ b/dataRetriever/txpool/shardedTxPool.go @@ -55,7 +55,7 @@ func NewShardedTxPool(args ArgShardedTxPool) (dataRetriever.ShardedDataCacherNot CountThreshold: args.Config.Size / numCaches, CountPerSenderThreshold: args.Config.SizePerSender, NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, - MinGasPriceMicroErd: uint32(args.MinGasPrice / oneBillion), + MinGasPriceNanoErd: uint32(args.MinGasPrice / oneBillion), } cacheConfigPrototypeForSelfShard := cacheConfigPrototype diff --git a/dataRetriever/txpool/shardedTxPool_test.go b/dataRetriever/txpool/shardedTxPool_test.go index 6cfc3f4443..a0b3a8b920 100644 --- a/dataRetriever/txpool/shardedTxPool_test.go +++ b/dataRetriever/txpool/shardedTxPool_test.go @@ -91,7 +91,7 @@ func Test_NewShardedTxPool_ComputesCacheConfig(t *testing.T) { require.Equal(t, uint32(100000), pool.cacheConfigPrototype.CountThreshold) require.Equal(t, uint32(1000), pool.cacheConfigPrototype.CountPerSenderThreshold) require.Equal(t, uint32(100), pool.cacheConfigPrototype.NumSendersToEvictInOneStep) - require.Equal(t, uint32(200), pool.cacheConfigPrototype.MinGasPriceMicroErd) + require.Equal(t, uint32(200), pool.cacheConfigPrototype.MinGasPriceNanoErd) require.Equal(t, uint32(291271110), pool.cacheConfigPrototypeForSelfShard.NumBytesThreshold) require.Equal(t, uint32(500000), pool.cacheConfigPrototypeForSelfShard.CountThreshold) } diff --git a/storage/txcache/config.go b/storage/txcache/config.go index 9c0c276232..62ee3a08b0 100644 --- a/storage/txcache/config.go +++ b/storage/txcache/config.go @@ -12,7 +12,7 @@ type CacheConfig struct { CountThreshold uint32 CountPerSenderThreshold uint32 NumSendersToEvictInOneStep uint32 - MinGasPriceMicroErd uint32 + MinGasPriceNanoErd uint32 } func (config *CacheConfig) verify() error { @@ -32,8 +32,8 @@ func (config *CacheConfig) verify() error { return fmt.Errorf("%w: config.CountPerSenderThreshold is invalid", errInvalidCacheConfig) } - if config.MinGasPriceMicroErd == 0 { - return fmt.Errorf("%w: config.MinGasPriceMicroErd is invalid", errInvalidCacheConfig) + if config.MinGasPriceNanoErd == 0 { + return fmt.Errorf("%w: config.MinGasPriceNanoErd is invalid", errInvalidCacheConfig) } if config.EvictionEnabled { diff --git a/storage/txcache/eviction_test.go b/storage/txcache/eviction_test.go index fb08dfc434..30943d86f5 100644 --- a/storage/txcache/eviction_test.go +++ b/storage/txcache/eviction_test.go @@ -18,7 +18,7 @@ func TestEviction_EvictSendersWhileTooManyTxs(t *testing.T) { NumSendersToEvictInOneStep: 20, NumBytesThreshold: math.MaxUint32, NumBytesPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -55,7 +55,7 @@ func TestEviction_EvictSendersWhileTooManyBytes(t *testing.T) { NumBytesThreshold: numBytesPerTx * 100, NumBytesPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 20, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -65,7 +65,7 @@ func TestEviction_EvictSendersWhileTooManyBytes(t *testing.T) { // 200 senders, each with 1 transaction for index := 0; index < 200; index++ { sender := string(createFakeSenderAddress(index)) - cache.AddTx(createTxWithParams([]byte{byte(index)}, sender, uint64(1), uint64(numBytesPerTx), 10000, 100*oneTrilion)) + cache.AddTx(createTxWithParams([]byte{byte(index)}, sender, uint64(1), uint64(numBytesPerTx), 10000, 100*oneBillion)) } require.Equal(t, int64(200), cache.txListBySender.counter.Get()) @@ -90,16 +90,16 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfCount(t *testing.T) { CountThreshold: 2, CountPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 2, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) require.Nil(t, err) require.NotNil(t, cache) - cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 1000, 100000, 100*oneTrilion)) - cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 1000, 100000, 100*oneTrilion)) - cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 1000, 100000, 700*oneTrilion)) + cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 1000, 100000, 100*oneBillion)) + cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 1000, 100000, 100*oneBillion)) + cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 1000, 100000, 700*oneBillion)) cache.doEviction() require.Equal(t, uint32(2), cache.evictionJournal.passOneNumTxs) @@ -122,16 +122,16 @@ func TestEviction_DoEvictionDoneInPassTwo_BecauseOfSize(t *testing.T) { NumBytesThreshold: 1000, NumBytesPerSenderThreshold: math.MaxUint32, NumSendersToEvictInOneStep: 2, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) require.Nil(t, err) require.NotNil(t, cache) - cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 800, 100000, 100*oneTrilion)) - cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 500, 100000, 100*oneTrilion)) - cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 200, 100000, 700*oneTrilion)) + cache.AddTx(createTxWithParams([]byte("hash-alice"), "alice", uint64(1), 800, 100000, 100*oneBillion)) + cache.AddTx(createTxWithParams([]byte("hash-bob"), "bob", uint64(1), 500, 100000, 100*oneBillion)) + cache.AddTx(createTxWithParams([]byte("hash-carol"), "carol", uint64(1), 200, 100000, 700*oneBillion)) require.InDelta(t, float64(19.50394606), cache.getRawScoreOfSender("alice"), delta) require.InDelta(t, float64(23.68494667), cache.getRawScoreOfSender("bob"), delta) @@ -157,7 +157,7 @@ func TestEviction_doEvictionDoesNothingWhenAlreadyInProgress(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -180,7 +180,7 @@ func TestEviction_evictSendersInLoop_CoverLoopBreak_WhenSmallBatch(t *testing.T) NumSendersToEvictInOneStep: 42, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -205,7 +205,7 @@ func TestEviction_evictSendersWhile_ShouldContinueBreak(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -239,7 +239,7 @@ func Test_AddWithEviction_UniformDistribution_25000x10(t *testing.T) { NumSendersToEvictInOneStep: dataRetriever.TxPoolNumSendersToEvictInOneStep, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } numSenders := 25000 diff --git a/storage/txcache/monitoring_test.go b/storage/txcache/monitoring_test.go index 4e1988ccfa..23a27ca6d4 100644 --- a/storage/txcache/monitoring_test.go +++ b/storage/txcache/monitoring_test.go @@ -16,7 +16,7 @@ func TestMonitoring_numTxAddedAndRemovedDuringEviction(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) @@ -48,7 +48,7 @@ func TestMonitoring_numTxAddedAndRemovedBetweenSelections(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } cache, err := NewTxCache(config) diff --git a/storage/txcache/testutils_test.go b/storage/txcache/testutils_test.go index 9b9ee67379..a4511b3e29 100644 --- a/storage/txcache/testutils_test.go +++ b/storage/txcache/testutils_test.go @@ -11,11 +11,11 @@ import ( ) const oneMilion = 1000000 -const oneTrilion = oneMilion * oneMilion +const oneBillion = oneMilion * 1000 const delta = 0.00000001 -func toMicroERD(erd uint64) uint64 { - return erd * 1000000 +func toNanoERD(erd float64) uint64 { + return uint64(erd * float64(1000000000)) } func kBToBytes(kB float32) uint64 { diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index 6d428a5f13..b207981407 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -19,7 +19,7 @@ func Test_NewTxCache(t *testing.T) { NumChunksHint: 16, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } evictionConfig := CacheConfig{ @@ -27,7 +27,7 @@ func Test_NewTxCache(t *testing.T) { NumChunksHint: 16, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, EvictionEnabled: true, NumBytesThreshold: math.MaxUint32, CountThreshold: math.MaxUint32, @@ -55,8 +55,8 @@ func Test_NewTxCache(t *testing.T) { requireErrorOnNewTxCache(t, badConfig, "config.CountPerSenderThreshold") badConfig = config - badConfig.MinGasPriceMicroErd = 0 - requireErrorOnNewTxCache(t, badConfig, "config.MinGasPriceMicroErd") + badConfig.MinGasPriceNanoErd = 0 + requireErrorOnNewTxCache(t, badConfig, "config.MinGasPriceNanoErd") badConfig = evictionConfig badConfig.NumBytesThreshold = 0 @@ -351,7 +351,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } // 11 * 10 @@ -371,7 +371,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumSendersToEvictInOneStep: 1, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, } // 100 * 1000 @@ -417,8 +417,8 @@ func TestTxCache_ConcurrentMutationAndSelection(t *testing.T) { cache := newUnconstrainedCacheToTest() // Alice will quickly move between two score buckets (chunks) - cheapTransaction := createTxWithParams([]byte("alice-x-o"), "alice", 0, 128, 50000, 100*oneTrilion) - expensiveTransaction := createTxWithParams([]byte("alice-x-1"), "alice", 1, 128, 50000, 300*oneTrilion) + cheapTransaction := createTxWithParams([]byte("alice-x-o"), "alice", 0, 128, 50000, 100*oneBillion) + expensiveTransaction := createTxWithParams([]byte("alice-x-1"), "alice", 1, 128, 50000, 300*oneBillion) cache.AddTx(cheapTransaction) cache.AddTx(expensiveTransaction) @@ -457,7 +457,7 @@ func newUnconstrainedCacheToTest() *TxCache { NumChunksHint: 16, NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, }) if err != nil { panic(fmt.Sprintf("newUnconstrainedCacheToTest(): %s", err)) @@ -472,7 +472,7 @@ func newCacheToTest(numBytesPerSenderThreshold uint32, countPerSenderThreshold u NumChunksHint: 16, NumBytesPerSenderThreshold: numBytesPerSenderThreshold, CountPerSenderThreshold: countPerSenderThreshold, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, }) if err != nil { panic(fmt.Sprintf("newCacheToTest(): %s", err)) diff --git a/storage/txcache/txListForSenderAsSortedMapItem.go b/storage/txcache/txListForSenderAsSortedMapItem.go index df567f4446..0fa62379e3 100644 --- a/storage/txcache/txListForSenderAsSortedMapItem.go +++ b/storage/txcache/txListForSenderAsSortedMapItem.go @@ -13,10 +13,10 @@ type senderScoreParams struct { count uint64 // Size is in bytes size uint64 - // Fee is in micro ERD + // Fee is in nano ERD fee uint64 gas uint64 - // Price is in micro ERD + // Price is in nano ERD minGasPrice uint32 } @@ -41,7 +41,7 @@ func (listForSender *txListForSender) computeRawScore() float64 { gas := listForSender.totalGas.GetUint64() size := listForSender.totalBytes.GetUint64() count := listForSender.countTx() - minGasPrice := listForSender.cacheConfig.MinGasPriceMicroErd + minGasPrice := listForSender.cacheConfig.MinGasPriceNanoErd return computeSenderScore(senderScoreParams{count: count, size: size, fee: fee, gas: gas, minGasPrice: minGasPrice}) } @@ -59,8 +59,8 @@ func (listForSender *txListForSender) computeRawScore() float64 { // For asymptoticScore, see (https://en.wikipedia.org/wiki/Logistic_function) // // Where: -// - PPUAvg: average gas points (fee) per processing unit, in micro ERD -// - PPUMin: minimum gas points (fee) per processing unit (given by economics.toml), in micro ERD +// - PPUAvg: average gas points (fee) per processing unit, in nano ERD +// - PPUMin: minimum gas points (fee) per processing unit (given by economics.toml), in nano ERD // - txCount: number of transactions // - txSize: size of transactions, in kB (1000 bytes) // diff --git a/storage/txcache/txListForSenderAsSortedMapItem_test.go b/storage/txcache/txListForSenderAsSortedMapItem_test.go index 2841954609..369671cd7d 100644 --- a/storage/txcache/txListForSenderAsSortedMapItem_test.go +++ b/storage/txcache/txListForSenderAsSortedMapItem_test.go @@ -9,9 +9,9 @@ import ( func TestSenderAsBucketSortedMapItem_ComputeScore(t *testing.T) { list := newUnconstrainedListToTest() - list.AddTx(createTxWithParams([]byte("a"), ".", 1, 1000, 200000, 100*oneTrilion)) - list.AddTx(createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneTrilion)) - list.AddTx(createTxWithParams([]byte("c"), ".", 1, 500, 100000, 100*oneTrilion)) + list.AddTx(createTxWithParams([]byte("a"), ".", 1, 1000, 200000, 100*oneBillion)) + list.AddTx(createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneBillion)) + list.AddTx(createTxWithParams([]byte("c"), ".", 1, 500, 100000, 100*oneBillion)) require.Equal(t, uint64(3), list.countTx()) require.Equal(t, int64(2000), list.totalBytes.Get()) @@ -24,9 +24,9 @@ func TestSenderAsBucketSortedMapItem_ComputeScore(t *testing.T) { func TestSenderAsBucketSortedMapItem_ScoreFluctuatesDeterministicallyWhenTransactionsAreAddedOrRemoved(t *testing.T) { list := newUnconstrainedListToTest() - A := createTxWithParams([]byte("A"), ".", 1, 1000, 200000, 100*oneTrilion) - B := createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneTrilion) - C := createTxWithParams([]byte("c"), ".", 1, 500, 100000, 100*oneTrilion) + A := createTxWithParams([]byte("A"), ".", 1, 1000, 200000, 100*oneBillion) + B := createTxWithParams([]byte("b"), ".", 1, 500, 100000, 100*oneBillion) + C := createTxWithParams([]byte("c"), ".", 1, 500, 100000, 100*oneBillion) scoreNone := int(list.ComputeScore()) list.AddTx(A) @@ -55,23 +55,23 @@ func TestSenderAsBucketSortedMapItem_ScoreFluctuatesDeterministicallyWhenTransac } func Test_computeSenderScore(t *testing.T) { - score := computeSenderScore(senderScoreParams{count: 14000, size: kBToBytes(100000), fee: toMicroERD(300000), gas: 2500000000, minGasPrice: 100}) + score := computeSenderScore(senderScoreParams{count: 14000, size: kBToBytes(100000), fee: toNanoERD(300), gas: 2500000000, minGasPrice: 100}) require.InDelta(t, float64(0.1789683371), score, delta) - score = computeSenderScore(senderScoreParams{count: 19000, size: kBToBytes(3000), fee: toMicroERD(2300000), gas: 19000000000, minGasPrice: 100}) + score = computeSenderScore(senderScoreParams{count: 19000, size: kBToBytes(3000), fee: toNanoERD(2300), gas: 19000000000, minGasPrice: 100}) require.InDelta(t, float64(0.2517997181), score, delta) - score = computeSenderScore(senderScoreParams{count: 3, size: kBToBytes(2), fee: toMicroERD(40), gas: 400000, minGasPrice: 100}) + score = computeSenderScore(senderScoreParams{count: 3, size: kBToBytes(2), fee: toNanoERD(0.04), gas: 400000, minGasPrice: 100}) require.InDelta(t, float64(5.795382396), score, delta) - score = computeSenderScore(senderScoreParams{count: 1, size: kBToBytes(0.3), fee: toMicroERD(50), gas: 100000, minGasPrice: 100}) + score = computeSenderScore(senderScoreParams{count: 1, size: kBToBytes(0.3), fee: toNanoERD(0.05), gas: 100000, minGasPrice: 100}) require.InDelta(t, float64(100), score, delta) } func Benchmark_computeSenderScore(b *testing.B) { for i := 0; i < b.N; i++ { for j := uint64(0); j < 10000000; j++ { - computeSenderScore(senderScoreParams{count: j, size: (j + 1) * 500, fee: toMicroERD(11 * j), gas: 100000 * j}) + computeSenderScore(senderScoreParams{count: j, size: (j + 1) * 500, fee: toNanoERD(float64(0.011) * float64(j)), gas: 100000 * j}) } } } diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 30d1055267..63693efefd 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -344,7 +344,7 @@ func newUnconstrainedListToTest() *txListForSender { return newTxListForSender(".", &CacheConfig{ NumBytesPerSenderThreshold: math.MaxUint32, CountPerSenderThreshold: math.MaxUint32, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, }, func(value *txListForSender) {}) } @@ -352,6 +352,6 @@ func newListToTest(numBytesThreshold uint32, countThreshold uint32) *txListForSe return newTxListForSender(".", &CacheConfig{ NumBytesPerSenderThreshold: numBytesThreshold, CountPerSenderThreshold: countThreshold, - MinGasPriceMicroErd: 100, + MinGasPriceNanoErd: 100, }, func(value *txListForSender) {}) } diff --git a/storage/txcache/txMeasures.go b/storage/txcache/txMeasures.go index 0dab0cada0..7b198faa8c 100644 --- a/storage/txcache/txMeasures.go +++ b/storage/txcache/txMeasures.go @@ -14,15 +14,14 @@ func estimateTxGas(tx *WrappedTransaction) uint64 { return gasLimit } -// estimateTxFee returns an approximation for the cost of a transaction, in micro ERD (1/1000000 ERD) +// estimateTxFee returns an approximation for the cost of a transaction, in nano ERD // TODO: switch to integer operations (as opposed to float operations). // TODO: do not assume the order of magnitude of minGasPrice. func estimateTxFee(tx *WrappedTransaction) uint64 { - // In order to obtain the result as micro ERD, we have to divide by 10^12, one trillion (since ~1 ERD accounts for ~10^18 gas currency units at the ~minimum price) - // In order to have better precision, we divide each of the factors by 10^6, one million - const SquareRootOfOneTrillion = 1000000 - gasLimit := float32(tx.Tx.GetGasLimit()) / SquareRootOfOneTrillion - gasPrice := float32(tx.Tx.GetGasPrice()) / SquareRootOfOneTrillion - feeInMicroERD := gasLimit * gasPrice - return uint64(feeInMicroERD) + // In order to obtain the result as nano ERD (not as "atomic" 10^-18 ERD), we have to divide by 10^9 + // In order to have better precision, we divide the factors by 10^6, and 10^3 respectively + gasLimit := float32(tx.Tx.GetGasLimit()) / 1000000 + gasPrice := float32(tx.Tx.GetGasPrice()) / 1000 + feeInNanoERD := gasLimit * gasPrice + return uint64(feeInNanoERD) } From 9c169a754cf1ce022388efd359add02161f8e61a Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 21:48:15 +0300 Subject: [PATCH 29/79] Remove log. --- storage/txcache/txCache.go | 1 - 1 file changed, 1 deletion(-) diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index 88c8d9bd73..efef03b0d8 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -77,7 +77,6 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { } if len(evicted) > 0 { - log.Trace("TxCache.AddTx()", "len(evicted)", len(evicted)) cache.txByHash.RemoveTxsBulk(evicted) } From 7f50aecb4c135be969cc8824f1f09fa3a9d9172f Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 May 2020 22:35:22 +0300 Subject: [PATCH 30/79] Fix after self review. --- dataRetriever/txpool/interface.go | 1 - storage/txcache/eviction.go | 19 +++++++------------ storage/txcache/testutils_test.go | 8 ++++---- storage/txcache/txByHashMap.go | 2 +- storage/txcache/txCache.go | 1 - storage/txcache/txCache_test.go | 12 ++++++------ storage/txcache/txListForSender.go | 9 +++++---- storage/txcache/txListForSender_test.go | 10 +++++----- 8 files changed, 28 insertions(+), 34 deletions(-) diff --git a/dataRetriever/txpool/interface.go b/dataRetriever/txpool/interface.go index 5fcc747837..bcf9c2fb30 100644 --- a/dataRetriever/txpool/interface.go +++ b/dataRetriever/txpool/interface.go @@ -13,5 +13,4 @@ type txCache interface { RemoveTxByHash(txHash []byte) error CountTx() int64 ForEachTransaction(function txcache.ForEachTransaction) - SelectTransactions(numRequested int, batchSizePerSender int) []*txcache.WrappedTransaction } diff --git a/storage/txcache/eviction.go b/storage/txcache/eviction.go index d014f9fb57..81c266568d 100644 --- a/storage/txcache/eviction.go +++ b/storage/txcache/eviction.go @@ -11,12 +11,7 @@ func (cache *TxCache) doEviction() { return } - tooManyBytes := cache.areThereTooManyBytes() - tooManyTxs := cache.areThereTooManyTxs() - tooManySenders := cache.areThereTooManySenders() - - isCapacityExceeded := tooManyBytes || tooManyTxs || tooManySenders - if !isCapacityExceeded { + if !cache.isCapacityExceeded() { return } @@ -30,7 +25,7 @@ func (cache *TxCache) doEviction() { stopWatch := cache.monitorEvictionStart() - if cache.shouldContinueEvictingSenders() { + if cache.isCapacityExceeded() { cache.makeSnapshotOfSenders() journal.passOneNumSteps, journal.passOneNumTxs, journal.passOneNumSenders = cache.evictSendersInLoop() journal.evictionPerformed = true @@ -49,6 +44,10 @@ func (cache *TxCache) destroySnapshotOfSenders() { cache.evictionSnapshotOfSenders = nil } +func (cache *TxCache) isCapacityExceeded() bool { + return cache.areThereTooManyBytes() || cache.areThereTooManySenders() || cache.areThereTooManyTxs() +} + func (cache *TxCache) areThereTooManyBytes() bool { numBytes := cache.NumBytes() tooManyBytes := numBytes > int64(cache.config.NumBytesThreshold) @@ -67,10 +66,6 @@ func (cache *TxCache) areThereTooManyTxs() bool { return tooManyTxs } -func (cache *TxCache) shouldContinueEvictingSenders() bool { - return cache.areThereTooManyTxs() || cache.areThereTooManySenders() || cache.areThereTooManyBytes() -} - // This is called concurrently by two goroutines: the eviction one and the sweeping one func (cache *TxCache) doEvictItems(txsToEvict txHashes, sendersToEvict []string) (countTxs uint32, countSenders uint32) { countTxs = cache.txByHash.RemoveTxsBulk(txsToEvict) @@ -79,7 +74,7 @@ func (cache *TxCache) doEvictItems(txsToEvict txHashes, sendersToEvict []string) } func (cache *TxCache) evictSendersInLoop() (uint32, uint32, uint32) { - return cache.evictSendersWhile(cache.shouldContinueEvictingSenders) + return cache.evictSendersWhile(cache.isCapacityExceeded) } // evictSendersWhileTooManyTxs removes transactions in a loop, as long as "shouldContinue" is true diff --git a/storage/txcache/testutils_test.go b/storage/txcache/testutils_test.go index a4511b3e29..83c1cee3cb 100644 --- a/storage/txcache/testutils_test.go +++ b/storage/txcache/testutils_test.go @@ -27,11 +27,11 @@ func (cache *TxCache) areInternalMapsConsistent() bool { internalMapBySender := cache.txListBySender senders := internalMapBySender.getSnapshotAscending() - numTransactionsByHash := len(internalMapByHash.keys()) - numTransactionsBySender := 0 + numTransactionsInMapByHash := len(internalMapByHash.keys()) + numTransactionsInMapBySender := 0 for _, sender := range senders { - numTransactionsBySender += int(sender.countTx()) + numTransactionsInMapBySender += int(sender.countTx()) for _, hash := range sender.getTxHashesAsStrings() { _, ok := internalMapByHash.getTx(hash) @@ -41,7 +41,7 @@ func (cache *TxCache) areInternalMapsConsistent() bool { } } - if numTransactionsBySender != numTransactionsByHash { + if numTransactionsInMapBySender != numTransactionsInMapByHash { return false } diff --git a/storage/txcache/txByHashMap.go b/storage/txcache/txByHashMap.go index 28372087d8..16f26a213e 100644 --- a/storage/txcache/txByHashMap.go +++ b/storage/txcache/txByHashMap.go @@ -65,7 +65,7 @@ func (txMap *txByHashMap) RemoveTxsBulk(txHashes txHashes) uint32 { } newCount := uint32(txMap.counter.Get()) - // TODO: Check this for overflow as well? + // TODO: Check this for overflow as well, then fix in EN-6299 numRemoved := oldCount - newCount return numRemoved } diff --git a/storage/txcache/txCache.go b/storage/txcache/txCache.go index efef03b0d8..69d09a833b 100644 --- a/storage/txcache/txCache.go +++ b/storage/txcache/txCache.go @@ -36,7 +36,6 @@ func NewTxCache(config CacheConfig) (*TxCache, error) { err := config.verify() if err != nil { - log.Error("NewTxCache config.verify()", "err", err) return nil, err } diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index b207981407..b04a9cec2b 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -22,7 +22,7 @@ func Test_NewTxCache(t *testing.T) { MinGasPriceNanoErd: 100, } - evictionConfig := CacheConfig{ + withEvictionConfig := CacheConfig{ Name: "test", NumChunksHint: 16, NumBytesPerSenderThreshold: math.MaxUint32, @@ -58,15 +58,15 @@ func Test_NewTxCache(t *testing.T) { badConfig.MinGasPriceNanoErd = 0 requireErrorOnNewTxCache(t, badConfig, "config.MinGasPriceNanoErd") - badConfig = evictionConfig + badConfig = withEvictionConfig badConfig.NumBytesThreshold = 0 requireErrorOnNewTxCache(t, badConfig, "config.NumBytesThreshold") - badConfig = evictionConfig + badConfig = withEvictionConfig badConfig.CountThreshold = 0 requireErrorOnNewTxCache(t, badConfig, "config.CountThreshold") - badConfig = evictionConfig + badConfig = withEvictionConfig badConfig.NumSendersToEvictInOneStep = 0 requireErrorOnNewTxCache(t, badConfig, "config.NumSendersToEvictInOneStep") } @@ -110,7 +110,7 @@ func Test_AddNilTx_DoesNothing(t *testing.T) { require.Nil(t, foundTx) } -func Test_AddTx_AppliesSizeConstraintsPerSender_NumTransactions(t *testing.T) { +func Test_AddTx_AppliesSizeConstraintsPerSenderForNumTransactions(t *testing.T) { cache := newCacheToTest(math.MaxUint32, 3) cache.AddTx(createTx([]byte("tx-alice-1"), "alice", 1)) @@ -128,7 +128,7 @@ func Test_AddTx_AppliesSizeConstraintsPerSender_NumTransactions(t *testing.T) { require.True(t, cache.areInternalMapsConsistent()) } -func Test_AddTx_AppliesSizeConstraintsPerSender_NumBytes(t *testing.T) { +func Test_AddTx_AppliesSizeConstraintsPerSenderForNumBytes(t *testing.T) { cache := newCacheToTest(1024, math.MaxUint32) cache.AddTx(createTxWithParams([]byte("tx-alice-1"), "alice", 1, 128, 42, 42)) diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index 07e4370802..b6932b59ae 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -72,15 +72,16 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) (bool, txHas func (listForSender *txListForSender) applySizeConstraints() txHashes { evictedTxHashes := make(txHashes, 0) + // Iterate back to front for element := listForSender.items.Back(); element != nil; element = element.Prev() { - if !listForSender.isLimitReached() { + if !listForSender.isCapacityExceeded() { break } listForSender.items.Remove(element) listForSender.onRemovedListElement(element) - // Keep track of removed transaction + // Keep track of removed transactions value := element.Value.(*WrappedTransaction) evictedTxHashes = append(evictedTxHashes, value.TxHash) } @@ -88,7 +89,7 @@ func (listForSender *txListForSender) applySizeConstraints() txHashes { return evictedTxHashes } -func (listForSender *txListForSender) isLimitReached() bool { +func (listForSender *txListForSender) isCapacityExceeded() bool { maxBytes := int64(listForSender.cacheConfig.NumBytesPerSenderThreshold) maxNumTxs := uint64(listForSender.cacheConfig.CountPerSenderThreshold) tooManyBytes := listForSender.totalBytes.Get() > maxBytes @@ -123,7 +124,7 @@ func (listForSender *txListForSender) findInsertionPlace(incomingTx *WrappedTran } if nonce == incomingNonce && gasPrice > incomingGasPrice { - // The incoming transaction will be placed right after the existing one (with higher price). + // The incoming transaction will be placed right after the existing one, which has same nonce but higher price. return element, nil } diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index 63693efefd..a842a94679 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -43,7 +43,7 @@ func TestListForSender_AddTx_IgnoresDuplicates(t *testing.T) { require.False(t, added) } -func TestListForSender_AddTx_AppliesSizeConstraints_NumTransactions(t *testing.T) { +func TestListForSender_AddTx_AppliesSizeConstraintsForNumTransactions(t *testing.T) { list := newListToTest(math.MaxUint32, 3) list.AddTx(createTx([]byte("tx1"), ".", 1)) @@ -56,18 +56,18 @@ func TestListForSender_AddTx_AppliesSizeConstraints_NumTransactions(t *testing.T require.ElementsMatch(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) - // Gives priority to higher gas - undesirably to some extent, "tx3" is evicted + // Gives priority to higher gas - though undesirably to some extent, "tx3" is evicted _, evicted = list.AddTx(createTxWithParams([]byte("tx2++"), ".", 2, 128, 42, 42)) require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) require.ElementsMatch(t, []string{"tx3"}, hashesAsStrings(evicted)) - // Undesirably to some extent, "tx3++"" is added, then evicted + // Though Undesirably to some extent, "tx3++"" is added, then evicted _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 3, 128, 42, 42)) require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) require.ElementsMatch(t, []string{"tx3++"}, hashesAsStrings(evicted)) } -func TestListForSender_AddTx_AppliesSizeConstraints_NumBytes(t *testing.T) { +func TestListForSender_AddTx_AppliesSizeConstraintsForNumBytes(t *testing.T) { list := newListToTest(1024, math.MaxUint32) list.AddTx(createTxWithParams([]byte("tx1"), ".", 1, 128, 42, 42)) @@ -85,7 +85,7 @@ func TestListForSender_AddTx_AppliesSizeConstraints_NumBytes(t *testing.T) { require.ElementsMatch(t, []string{"tx1", "tx2", "tx3", "tx4"}, list.getTxHashesAsStrings()) require.ElementsMatch(t, []string{"tx5--"}, hashesAsStrings(evicted)) - // Gives priority to higher gas - undesirably to some extent, "tx4" is evicted + // Gives priority to higher gas - though undesirably to some extent, "tx4" is evicted _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 4, 256, 42, 100)) require.ElementsMatch(t, []string{"tx1", "tx2", "tx3++", "tx3"}, list.getTxHashesAsStrings()) require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) From b30af75d2458747a4cacf8e62793107a7e85a6f1 Mon Sep 17 00:00:00 2001 From: andrei-marinica Date: Wed, 13 May 2020 09:53:36 +0300 Subject: [PATCH 31/79] fixed go.mod --- go.mod | 2 -- go.sum | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 5abe95ad5d..5fa1300a46 100644 --- a/go.mod +++ b/go.mod @@ -47,5 +47,3 @@ require ( golang.org/x/net v0.0.0-20190620200207-3b0461eec859 gopkg.in/go-playground/validator.v8 v8.18.2 ) - -replace github.com/ElrondNetwork/arwen-wasm-vm => ../arwen-wasm-vm diff --git a/go.sum b/go.sum index fb133aaa92..3fe0b2c741 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.17 h1:+kbE3wwOY1BiPRlH0AGQQJ77anpevogCDsTdFNc3OdU= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.17/go.mod h1:cyBSzwbWSGqXJz5excz9PhF4FOhWvS3EFggiFReHsdU= github.com/ElrondNetwork/big-int-util v0.0.5 h1:e/9kK++9ZH/SdIYqLSUPRFYrDZmDWDgff3/7SCydq5I= github.com/ElrondNetwork/big-int-util v0.0.5/go.mod h1:96viBvoTXLjZOhEvE0D+QnAwg1IJLPAK6GVHMbC7Aw4= github.com/ElrondNetwork/concurrent-map v0.1.2 h1:mr2sVF2IPDsJO8DNGzCUiNQOJcadHuIRVZn+QFnCBlE= From 28c52385459358fb9e489d66feecf652fa823857 Mon Sep 17 00:00:00 2001 From: andrei-marinica Date: Wed, 13 May 2020 09:54:03 +0300 Subject: [PATCH 32/79] fixed cross-shard delegation test --- .../smartContract/scCallingSC_test.go | 26 ++++++++++++++----- integrationTests/testProcessorNode.go | 4 +-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/integrationTests/multiShard/smartContract/scCallingSC_test.go b/integrationTests/multiShard/smartContract/scCallingSC_test.go index ed54e2ec8e..6d743ac42c 100644 --- a/integrationTests/multiShard/smartContract/scCallingSC_test.go +++ b/integrationTests/multiShard/smartContract/scCallingSC_test.go @@ -565,22 +565,36 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { // mint smart contract holders shardNode := findAnyShardNode(nodes) delegateSCOwner := shardNode.OwnAccount.Address - totalStake := shardNode.EconomicsData.GenesisNodePrice() + stakePerNode := shardNode.EconomicsData.GenesisNodePrice() + totalStake := stakePerNode // 1 node only in this test nodeSharePer10000 := 3000 + time_before_force_unstake := 680400 stakerBLSKey, _ := hex.DecodeString(strings.Repeat("a", 128*2)) stakerBLSSignature, _ := hex.DecodeString(strings.Repeat("c", 32*2)) // deploy the delegation smart contract delegateSCAddress := putDeploySCToDataPool( "./testdata/delegate/delegation.wasm", delegateSCOwner, 0, big.NewInt(0), - fmt.Sprintf("@%x@%x@%s", totalStake, nodeSharePer10000, hex.EncodeToString(factory2.AuctionSCAddress)), + fmt.Sprintf("@%x@%s@%x", nodeSharePer10000, hex.EncodeToString(factory2.AuctionSCAddress), time_before_force_unstake), nodes) shardNode.OwnAccount.Nonce++ nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) + // set number of nodes + setNrNodesTxData := "setNrNodes@1" + integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setNrNodesTxData) + + nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) + + // set stake per node + setStakePerNodeTxData := fmt.Sprintf("setStakePerNode@%x", stakePerNode) + integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setStakePerNodeTxData) + + nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) + // set BLS keys in the contract - setBlsTxData := "setBlsKeys@1@" + hex.EncodeToString(stakerBLSKey) + setBlsTxData := "setBlsKeys@" + hex.EncodeToString(stakerBLSKey) integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setBlsTxData) nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) @@ -608,7 +622,7 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { // check that delegation contract was correctly initialized by querying for total stake scQuery1 := &process.SCQuery{ ScAddress: delegateSCAddress, - FuncName: "getTotalStake", + FuncName: "getExpectedStake", Arguments: [][]byte{}, } vmOutput1, _ := shardNode.SCQueryService.ExecuteQuery(scQuery1) @@ -630,13 +644,13 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { // check that the staking transaction worked scQuery3 := &process.SCQuery{ ScAddress: delegateSCAddress, - FuncName: "getUnfilledStake", + FuncName: "getFilledStake", Arguments: [][]byte{}, } vmOutput3, _ := shardNode.SCQueryService.ExecuteQuery(scQuery3) assert.NotNil(t, vmOutput3) assert.Equal(t, len(vmOutput3.ReturnData), 1) - assert.True(t, len(vmOutput3.ReturnData[0]) == 0) // unfilled stake == 0 + assert.True(t, totalStake.Cmp(big.NewInt(0).SetBytes(vmOutput3.ReturnData[0])) == 0) // filled stake == total stake // check that the staking system smart contract has the value for _, node := range nodes { diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 04416e0ddd..b5a99c1a23 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -115,10 +115,10 @@ var TestBalanceComputationHandler, _ = preprocess.NewBalanceComputation() var MinTxGasPrice = uint64(10) // MinTxGasLimit defines minimum gas limit required by a transaction -var MinTxGasLimit = uint64(1000) +var MinTxGasLimit = uint64(10_000) // MaxGasLimitPerBlock defines maximum gas limit allowed per one block -const MaxGasLimitPerBlock = uint64(300000) +const MaxGasLimitPerBlock = uint64(3_000_000) const maxTxNonceDeltaAllowed = 8000 const minConnectedPeers = 0 From 53ebe73323e7bd304b3e797365222fb1e35e5b82 Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 13 May 2020 11:46:30 +0300 Subject: [PATCH 33/79] EN-6373 : fix after review --- epochStart/metachain/economics_test.go | 173 ++++++++++++++----------- 1 file changed, 99 insertions(+), 74 deletions(-) diff --git a/epochStart/metachain/economics_test.go b/epochStart/metachain/economics_test.go index a8b4c436ef..9d5e65e8b1 100644 --- a/epochStart/metachain/economics_test.go +++ b/epochStart/metachain/economics_test.go @@ -13,6 +13,7 @@ import ( "github.com/ElrondNetwork/elrond-go/dataRetriever" "github.com/ElrondNetwork/elrond-go/epochStart" "github.com/ElrondNetwork/elrond-go/epochStart/mock" + "github.com/ElrondNetwork/elrond-go/process" "github.com/ElrondNetwork/elrond-go/storage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -443,14 +444,67 @@ func TestEconomics_VerifyRewardsPerBlock_DifferentHitRates(t *testing.T) { } } +type testInput struct { + blockPerEpochOneShard uint64 + accumulatedFeesInEpoch *big.Int + devFeesInEpoch *big.Int +} + func TestComputeEndOfEpochEconomics(t *testing.T) { t.Parallel() - commAddress := "communityAddress" totalSupply, _ := big.NewInt(0).SetString("20000000000000000000000000000", 10) // 20 Billions ERD nodePrice, _ := big.NewInt(0).SetString("1000000000000000000000", 10) // 1000 ERD + roundDuration := 4 + + args := createArgsForComputeEndOfEpochEconomics(roundDuration, totalSupply, nodePrice) + ec, _ := NewEndOfEpochEconomicsDataCreator(args) + + epochDuration := numberOfSecondsInDay + roundsPerEpoch := uint64(epochDuration / roundDuration) + + testInputs := []testInput{ + {blockPerEpochOneShard: roundsPerEpoch, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 2, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 4, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 8, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 16, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 32, accumulatedFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, + {blockPerEpochOneShard: roundsPerEpoch / 64, accumulatedFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(10000000)}, + {blockPerEpochOneShard: roundsPerEpoch, accumulatedFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(30000000000000)}, + } + + rewardsPerBlock, _ := big.NewInt(0).SetString("84559445290038908043", 10) // *based on 0.1 inflation + for _, input := range testInputs { + meta := &block.MetaBlock{ + AccumulatedFeesInEpoch: input.accumulatedFeesInEpoch, + DevFeesInEpoch: input.devFeesInEpoch, + Epoch: 1, + Round: roundsPerEpoch, + Nonce: input.blockPerEpochOneShard, + EpochStart: block.EpochStart{ + LastFinalizedHeaders: []block.EpochStartShardData{ + {ShardID: 0, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, + {ShardID: 1, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, + }, + }, + } + + economicsBlock, err := ec.ComputeEndOfEpochEconomics(meta) + assert.Nil(t, err) + + verifyEconomicsBlock(t, economicsBlock, input, rewardsPerBlock, nodePrice, totalSupply, roundsPerEpoch, args.RewardsHandler) + } + +} + +func createArgsForComputeEndOfEpochEconomics( + roundDuration int, + totalSupply *big.Int, + nodePrice *big.Int, +) ArgsNewEpochEconomics { + commAddress := "communityAddress" - roundDur := 4 args := getArguments() args.RewardsHandler = &mock.RewardsHandlerStub{ MaxInflationRateCalled: func() float64 { @@ -468,7 +522,7 @@ func TestComputeEndOfEpochEconomics(t *testing.T) { } args.RoundTime = &mock.RoundTimeDurationHandler{ TimeDurationCalled: func() time.Duration { - return time.Duration(roundDur) * time.Second + return time.Duration(roundDuration) * time.Second }, } hdrPrevEpochStart := block.MetaBlock{ @@ -500,80 +554,51 @@ func TestComputeEndOfEpochEconomics(t *testing.T) { }, } - ec, _ := NewEndOfEpochEconomicsDataCreator(args) - - epochDuration := numberOfSecondsInDay - roundsPerEpoch := uint64(epochDuration / roundDur) - type testInput struct { - blockPerEpochOneShard uint64 - acFeesInEpoch *big.Int - devFeesInEpoch *big.Int - } - - testInpus := []testInput{ - {blockPerEpochOneShard: roundsPerEpoch, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 2, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 4, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 8, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 16, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 32, acFeesInEpoch: intToErd(1000), devFeesInEpoch: intToErd(1000)}, - {blockPerEpochOneShard: roundsPerEpoch / 64, acFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(10000000)}, - {blockPerEpochOneShard: roundsPerEpoch, acFeesInEpoch: intToErd(100000000000000), devFeesInEpoch: intToErd(30000000000000)}, - } - - rewardsPerBlock, _ := big.NewInt(0).SetString("84559445290038908043", 10) // *based on 0.1 inflation - for _, input := range testInpus { - meta := &block.MetaBlock{ - AccumulatedFeesInEpoch: input.acFeesInEpoch, - DevFeesInEpoch: input.devFeesInEpoch, - Epoch: 1, - Round: roundsPerEpoch, - Nonce: input.blockPerEpochOneShard, - EpochStart: block.EpochStart{ - LastFinalizedHeaders: []block.EpochStartShardData{ - {ShardID: 0, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, - {ShardID: 1, Round: roundsPerEpoch, Nonce: input.blockPerEpochOneShard}, - }, - }, - } - - economicsBlock, err := ec.ComputeEndOfEpochEconomics(meta) - assert.Nil(t, err) - - blocksPerEpochTotal := int64(input.blockPerEpochOneShard * 3) - hitRate := float64(input.blockPerEpochOneShard) / float64(roundsPerEpoch) * 100 - printEconomicsData(economicsBlock, hitRate, blocksPerEpochTotal) - - expectedTotalRewardsToBeDistributed := big.NewInt(0).Mul(rewardsPerBlock, big.NewInt(blocksPerEpochTotal)) - expectedNewTokens := big.NewInt(0).Sub(expectedTotalRewardsToBeDistributed, input.acFeesInEpoch) - if expectedNewTokens.Cmp(big.NewInt(0)) < 0 { - expectedNewTokens = big.NewInt(0) - expectedTotalRewardsToBeDistributed = input.acFeesInEpoch - } + return args +} - adjustedRewardsPerBlock := big.NewInt(0).Div(expectedTotalRewardsToBeDistributed, big.NewInt(blocksPerEpochTotal)) - - // subtract developer rewards per block - developerFeesPerBlock := big.NewInt(0).Div(input.devFeesInEpoch, big.NewInt(blocksPerEpochTotal)) - adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, developerFeesPerBlock) - // subtract leader percentage per block - rewardsForLeader := core.GetPercentageOfValue(input.acFeesInEpoch, args.RewardsHandler.LeaderPercentage()) - rewardsForLeaderPerBlock := big.NewInt(0).Div(rewardsForLeader, big.NewInt(blocksPerEpochTotal)) - adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, rewardsForLeaderPerBlock) - // communityPercentage - expectedCommunityRewards := core.GetPercentageOfValue(expectedTotalRewardsToBeDistributed, args.RewardsHandler.CommunityPercentage()) - // subtract community percentage per block - communityRewardsPerBlock := big.NewInt(0).Div(expectedCommunityRewards, big.NewInt(blocksPerEpochTotal)) - adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, communityRewardsPerBlock) - - assert.Equal(t, expectedNewTokens, economicsBlock.TotalNewlyMinted) - assert.Equal(t, big.NewInt(0).Add(totalSupply, expectedNewTokens), economicsBlock.TotalSupply) - assert.Equal(t, expectedTotalRewardsToBeDistributed, economicsBlock.TotalToDistribute) - assert.Equal(t, expectedCommunityRewards, economicsBlock.RewardsForCommunity) - assert.Equal(t, nodePrice, economicsBlock.NodePrice) - assert.Equal(t, adjustedRewardsPerBlock, economicsBlock.RewardsPerBlockPerNode) +func verifyEconomicsBlock( + t *testing.T, + economicsBlock *block.Economics, + input testInput, + rewardsPerBlock *big.Int, + nodePrice *big.Int, + totalSupply *big.Int, + roundsPerEpoch uint64, + rewardsHandler process.RewardsHandler, +) { + totalBlocksPerEpoch := int64(input.blockPerEpochOneShard * 3) + hitRate := float64(input.blockPerEpochOneShard) / float64(roundsPerEpoch) * 100 + printEconomicsData(economicsBlock, hitRate, totalBlocksPerEpoch) + + expectedTotalRewardsToBeDistributed := big.NewInt(0).Mul(rewardsPerBlock, big.NewInt(totalBlocksPerEpoch)) + expectedNewTokens := big.NewInt(0).Sub(expectedTotalRewardsToBeDistributed, input.accumulatedFeesInEpoch) + if expectedNewTokens.Cmp(big.NewInt(0)) < 0 { + expectedNewTokens = big.NewInt(0) + expectedTotalRewardsToBeDistributed = input.accumulatedFeesInEpoch } + adjustedRewardsPerBlock := big.NewInt(0).Div(expectedTotalRewardsToBeDistributed, big.NewInt(totalBlocksPerEpoch)) + + // subtract developer rewards per block + developerFeesPerBlock := big.NewInt(0).Div(input.devFeesInEpoch, big.NewInt(totalBlocksPerEpoch)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, developerFeesPerBlock) + // subtract leader percentage per block + rewardsForLeader := core.GetPercentageOfValue(input.accumulatedFeesInEpoch, rewardsHandler.LeaderPercentage()) + rewardsForLeaderPerBlock := big.NewInt(0).Div(rewardsForLeader, big.NewInt(totalBlocksPerEpoch)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, rewardsForLeaderPerBlock) + // communityPercentage + expectedCommunityRewards := core.GetPercentageOfValue(expectedTotalRewardsToBeDistributed, rewardsHandler.CommunityPercentage()) + // subtract community percentage per block + communityRewardsPerBlock := big.NewInt(0).Div(expectedCommunityRewards, big.NewInt(totalBlocksPerEpoch)) + adjustedRewardsPerBlock.Sub(adjustedRewardsPerBlock, communityRewardsPerBlock) + + assert.Equal(t, expectedNewTokens, economicsBlock.TotalNewlyMinted) + assert.Equal(t, big.NewInt(0).Add(totalSupply, expectedNewTokens), economicsBlock.TotalSupply) + assert.Equal(t, expectedTotalRewardsToBeDistributed, economicsBlock.TotalToDistribute) + assert.Equal(t, expectedCommunityRewards, economicsBlock.RewardsForCommunity) + assert.Equal(t, nodePrice, economicsBlock.NodePrice) + assert.Equal(t, adjustedRewardsPerBlock, economicsBlock.RewardsPerBlockPerNode) } func printEconomicsData(eb *block.Economics, hitRate float64, numBlocksTotal int64) { From 83e0fb5e19cf22860e697146f3b989d2fc04b580 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 13:51:55 +0300 Subject: [PATCH 34/79] export maxTrieLevelInMemory to config --- cmd/node/config/config.toml | 2 + cmd/node/factory/structs.go | 3 +- config/config.go | 2 + data/interface.go | 2 +- data/state/accountsDB_test.go | 3 +- data/syncer/baseAccountsSyncer.go | 38 ++++++------ data/syncer/userAccountsSyncer.go | 2 +- data/trie/branchNode.go | 6 +- data/trie/branchNode_test.go | 27 ++++----- data/trie/extensionNode.go | 6 +- data/trie/extensionNode_test.go | 24 ++++---- data/trie/factory/trieCreator.go | 6 +- data/trie/factory/trieCreator_test.go | 15 +++-- data/trie/interface.go | 4 +- data/trie/leafNode.go | 2 +- data/trie/leafNode_test.go | 14 ++--- data/trie/node.go | 11 ++-- data/trie/node_test.go | 12 ++-- data/trie/patriciaMerkleTrie.go | 23 +++++--- data/trie/patriciaMerkleTrie_test.go | 23 ++++---- data/trie/trieStorageManager.go | 3 +- data/trie/trieStorageManager_test.go | 3 +- epochStart/bootstrap/process.go | 38 +++++++----- factory/triesComponents.go | 12 +++- integrationTests/consensus/testInitializer.go | 3 +- .../longTests/storage/storage_test.go | 3 +- .../startInEpoch/startInEpoch_test.go | 14 ++++- .../multiShard/hardFork/hardFork_test.go | 1 + .../state/stateTrie/stateTrie_test.go | 18 ++++-- integrationTests/testInitializer.go | 7 ++- integrationTests/vm/testInitializer.go | 3 +- .../accountDBSyncerContainerFactory.go | 58 ++++++++++--------- update/factory/dataTrieFactory.go | 22 +++---- update/factory/exportHandlerFactory.go | 28 +++++---- 34 files changed, 256 insertions(+), 182 deletions(-) diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 1bfa8298da..235145f741 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -396,6 +396,8 @@ CheckpointRoundsModulus = 100 AccountsStatePruningEnabled = true PeerStatePruningEnabled = true + MaxStateTrieLevelInMemory = 5 + MaxPeerTrieLevelInMemory = 5 [BlockSizeThrottleConfig] MinSizeInBytes = 104857 # 104857 is 10% from 1MB diff --git a/cmd/node/factory/structs.go b/cmd/node/factory/structs.go index ec5d59ce00..4428dd26bb 100644 --- a/cmd/node/factory/structs.go +++ b/cmd/node/factory/structs.go @@ -1849,7 +1849,8 @@ func generateInMemoryAccountsAdapter( return nil, err } - tr, err := trie.NewTrie(trieStorage, marshalizer, hasher) + maxTrieLevelInMemory := uint(5) + tr, err := trie.NewTrie(trieStorage, marshalizer, hasher, maxTrieLevelInMemory) if err != nil { return nil, err } diff --git a/config/config.go b/config/config.go index fa2baebdbf..6333e39860 100644 --- a/config/config.go +++ b/config/config.go @@ -187,6 +187,8 @@ type StateTriesConfig struct { CheckpointRoundsModulus uint AccountsStatePruningEnabled bool PeerStatePruningEnabled bool + MaxStateTrieLevelInMemory uint + MaxPeerTrieLevelInMemory uint } // TrieStorageManagerConfig will hold config information about trie storage manager diff --git a/data/interface.go b/data/interface.go index e1a6e3a10a..4b0d638ac2 100644 --- a/data/interface.go +++ b/data/interface.go @@ -207,7 +207,7 @@ type StorageManager interface { // TrieFactory creates new tries type TrieFactory interface { - Create(config.StorageConfig, bool) (StorageManager, Trie, error) + Create(config.StorageConfig, bool, uint) (StorageManager, Trie, error) IsInterfaceNil() bool } diff --git a/data/state/accountsDB_test.go b/data/state/accountsDB_test.go index 33379f4a15..fb95e8520e 100644 --- a/data/state/accountsDB_test.go +++ b/data/state/accountsDB_test.go @@ -810,7 +810,8 @@ func TestAccountsDB_RevertToSnapshotShouldWork(t *testing.T) { hsh := mock.HasherMock{} accFactory := factory.NewAccountCreator() storageManager, _ := trie.NewTrieStorageManagerWithoutPruning(mock.NewMemDbMock()) - tr, _ := trie.NewTrie(storageManager, marsh, hsh) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(storageManager, marsh, hsh, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, hsh, marsh, accFactory) diff --git a/data/syncer/baseAccountsSyncer.go b/data/syncer/baseAccountsSyncer.go index 9549eb2543..14f83a244a 100644 --- a/data/syncer/baseAccountsSyncer.go +++ b/data/syncer/baseAccountsSyncer.go @@ -16,29 +16,31 @@ import ( ) type baseAccountsSyncer struct { - hasher hashing.Hasher - marshalizer marshal.Marshalizer - trieSyncers map[string]data.TrieSyncer - dataTries map[string]data.Trie - mutex sync.Mutex - trieStorageManager data.StorageManager - requestHandler trie.RequestHandler - waitTime time.Duration - shardId uint32 - cacher storage.Cacher - rootHash []byte + hasher hashing.Hasher + marshalizer marshal.Marshalizer + trieSyncers map[string]data.TrieSyncer + dataTries map[string]data.Trie + mutex sync.Mutex + trieStorageManager data.StorageManager + requestHandler trie.RequestHandler + waitTime time.Duration + shardId uint32 + cacher storage.Cacher + rootHash []byte + maxTrieLevelInMemory uint } const minWaitTime = time.Second // ArgsNewBaseAccountsSyncer defines the arguments needed for the new account syncer type ArgsNewBaseAccountsSyncer struct { - Hasher hashing.Hasher - Marshalizer marshal.Marshalizer - TrieStorageManager data.StorageManager - RequestHandler trie.RequestHandler - WaitTime time.Duration - Cacher storage.Cacher + Hasher hashing.Hasher + Marshalizer marshal.Marshalizer + TrieStorageManager data.StorageManager + RequestHandler trie.RequestHandler + WaitTime time.Duration + Cacher storage.Cacher + MaxTrieLevelInMemory uint } func checkArgs(args ArgsNewBaseAccountsSyncer) error { @@ -67,7 +69,7 @@ func checkArgs(args ArgsNewBaseAccountsSyncer) error { func (b *baseAccountsSyncer) syncMainTrie(rootHash []byte, trieTopic string, ctx context.Context) error { b.rootHash = rootHash - dataTrie, err := trie.NewTrie(b.trieStorageManager, b.marshalizer, b.hasher) + dataTrie, err := trie.NewTrie(b.trieStorageManager, b.marshalizer, b.hasher, b.maxTrieLevelInMemory) if err != nil { return err } diff --git a/data/syncer/userAccountsSyncer.go b/data/syncer/userAccountsSyncer.go index 8b59419546..7658000022 100644 --- a/data/syncer/userAccountsSyncer.go +++ b/data/syncer/userAccountsSyncer.go @@ -81,7 +81,7 @@ func (u *userAccountsSyncer) SyncAccounts(rootHash []byte) error { func (u *userAccountsSyncer) syncAccountDataTries(rootHashes [][]byte, ctx context.Context) error { for _, rootHash := range rootHashes { - dataTrie, err := trie.NewTrie(u.trieStorageManager, u.marshalizer, u.hasher) + dataTrie, err := trie.NewTrie(u.trieStorageManager, u.marshalizer, u.hasher, u.maxTrieLevelInMemory) if err != nil { return err } diff --git a/data/trie/branchNode.go b/data/trie/branchNode.go index c55af367d8..3249d12da5 100644 --- a/data/trie/branchNode.go +++ b/data/trie/branchNode.go @@ -240,7 +240,7 @@ func (bn *branchNode) hashNode() ([]byte, error) { return encodeNodeAndGetHash(bn) } -func (bn *branchNode) commit(force bool, level byte, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error { +func (bn *branchNode) commit(force bool, level byte, maxTrieLevelInMemory uint, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error { level++ err := bn.isEmptyOrNil() if err != nil { @@ -264,7 +264,7 @@ func (bn *branchNode) commit(force bool, level byte, originDb data.DBWriteCacher continue } - err = bn.children[i].commit(force, level, originDb, targetDb) + err = bn.children[i].commit(force, level, maxTrieLevelInMemory, originDb, targetDb) if err != nil { return err } @@ -274,7 +274,7 @@ func (bn *branchNode) commit(force bool, level byte, originDb data.DBWriteCacher if err != nil { return err } - if level == maxTrieLevelAfterCommit { + if uint(level) == maxTrieLevelInMemory { var collapsed node collapsed, err = bn.getCollapsed() if err != nil { diff --git a/data/trie/branchNode_test.go b/data/trie/branchNode_test.go index d53debce30..3fb2777eb5 100644 --- a/data/trie/branchNode_test.go +++ b/data/trie/branchNode_test.go @@ -187,9 +187,10 @@ func TestBranchNode_setRootHash(t *testing.T) { marsh, hsh := getTestMarshAndHasher() trieStorage1, _ := NewTrieStorageManager(db, marsh, hsh, cfg, &mock.EvictionWaitingList{}, config.TrieStorageManagerConfig{}) trieStorage2, _ := NewTrieStorageManager(db, marsh, hsh, cfg, &mock.EvictionWaitingList{}, config.TrieStorageManagerConfig{}) + maxTrieLevelInMemory := uint(5) - tr1, _ := NewTrie(trieStorage1, marsh, hsh) - tr2, _ := NewTrie(trieStorage2, marsh, hsh) + tr1, _ := NewTrie(trieStorage1, marsh, hsh, maxTrieLevelInMemory) + tr2, _ := NewTrie(trieStorage2, marsh, hsh, maxTrieLevelInMemory) maxIterations := 10000 for i := 0; i < maxIterations; i++ { @@ -348,7 +349,7 @@ func TestBranchNode_commit(t *testing.T) { hash, _ := encodeNodeAndGetHash(collapsedBn) _ = bn.setHash() - err := bn.commit(false, 0, db, db) + err := bn.commit(false, 0, 5, db, db) assert.Nil(t, err) encNode, _ := db.Get(hash) @@ -363,7 +364,7 @@ func TestBranchNode_commitEmptyNode(t *testing.T) { bn := emptyDirtyBranchNode() - err := bn.commit(false, 0, nil, nil) + err := bn.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrEmptyBranchNode)) } @@ -372,7 +373,7 @@ func TestBranchNode_commitNilNode(t *testing.T) { var bn *branchNode - err := bn.commit(false, 0, nil, nil) + err := bn.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrNilBranchNode)) } @@ -417,7 +418,7 @@ func TestBranchNode_resolveCollapsed(t *testing.T) { childPos := byte(2) _ = bn.setHash() - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) resolved, _ := newLeafNode([]byte("dog"), []byte("dog"), bn.marsh, bn.hasher) resolved.dirty = false resolved.hash = bn.EncodedChildren[childPos] @@ -518,7 +519,7 @@ func TestBranchNode_tryGetCollapsedNode(t *testing.T) { bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) _ = bn.setHash() - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) childPos := byte(2) key := append([]byte{childPos}, []byte("dog")...) @@ -644,7 +645,7 @@ func TestBranchNode_insertCollapsedNode(t *testing.T) { node, _ := newLeafNode(key, []byte("dogs"), bn.marsh, bn.hasher) _ = bn.setHash() - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) dirty, newBn, _, err := collapsedBn.insert(node, db) assert.True(t, dirty) @@ -663,7 +664,7 @@ func TestBranchNode_insertInStoredBnOnExistingPos(t *testing.T) { key := append([]byte{childPos}, []byte("dog")...) node, _ := newLeafNode(key, []byte("dogs"), bn.marsh, bn.hasher) - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) bnHash := bn.getHash() ln, _, _ := bn.getNext(key, db) lnHash := ln.getHash() @@ -684,7 +685,7 @@ func TestBranchNode_insertInStoredBnOnNilPos(t *testing.T) { key := append([]byte{nilChildPos}, []byte("dog")...) node, _ := newLeafNode(key, []byte("dogs"), bn.marsh, bn.hasher) - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) bnHash := bn.getHash() expectedHashes := [][]byte{bnHash} @@ -763,7 +764,7 @@ func TestBranchNode_deleteFromStoredBn(t *testing.T) { childPos := byte(2) lnKey := append([]byte{childPos}, []byte("dog")...) - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) bnHash := bn.getHash() ln, _, _ := bn.getNext(lnKey, db) lnHash := ln.getHash() @@ -845,7 +846,7 @@ func TestBranchNode_deleteCollapsedNode(t *testing.T) { db := mock.NewMemDbMock() bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) _ = bn.setHash() - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) childPos := byte(2) key := append([]byte{childPos}, []byte("dog")...) @@ -1017,7 +1018,7 @@ func TestBranchNode_getChildrenCollapsedBn(t *testing.T) { db := mock.NewMemDbMock() bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) - _ = bn.commit(true, 0, db, db) + _ = bn.commit(true, 0, 5, db, db) children, err := collapsedBn.getChildren(db) assert.Nil(t, err) diff --git a/data/trie/extensionNode.go b/data/trie/extensionNode.go index 3b02d8b803..ff2b86dd88 100644 --- a/data/trie/extensionNode.go +++ b/data/trie/extensionNode.go @@ -175,7 +175,7 @@ func (en *extensionNode) hashNode() ([]byte, error) { return encodeNodeAndGetHash(en) } -func (en *extensionNode) commit(force bool, level byte, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error { +func (en *extensionNode) commit(force bool, level byte, maxTrieLevelInMemory uint, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error { level++ err := en.isEmptyOrNil() if err != nil { @@ -195,7 +195,7 @@ func (en *extensionNode) commit(force bool, level byte, originDb data.DBWriteCac } if en.child != nil { - err = en.child.commit(force, level, originDb, targetDb) + err = en.child.commit(force, level, maxTrieLevelInMemory, originDb, targetDb) if err != nil { return err } @@ -206,7 +206,7 @@ func (en *extensionNode) commit(force bool, level byte, originDb data.DBWriteCac if err != nil { return err } - if level == maxTrieLevelAfterCommit { + if uint(level) == maxTrieLevelInMemory { var collapsed node collapsed, err = en.getCollapsed() if err != nil { diff --git a/data/trie/extensionNode_test.go b/data/trie/extensionNode_test.go index 13f764331d..995995014f 100644 --- a/data/trie/extensionNode_test.go +++ b/data/trie/extensionNode_test.go @@ -235,7 +235,7 @@ func TestExtensionNode_commit(t *testing.T) { hash, _ := encodeNodeAndGetHash(collapsedEn) _ = en.setHash() - err := en.commit(false, 0, db, db) + err := en.commit(false, 0, 5, db, db) assert.Nil(t, err) encNode, _ := db.Get(hash) @@ -251,7 +251,7 @@ func TestExtensionNode_commitEmptyNode(t *testing.T) { en := &extensionNode{} - err := en.commit(false, 0, nil, nil) + err := en.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrEmptyExtensionNode)) } @@ -260,7 +260,7 @@ func TestExtensionNode_commitNilNode(t *testing.T) { var en *extensionNode - err := en.commit(false, 0, nil, nil) + err := en.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrNilExtensionNode)) } @@ -273,7 +273,7 @@ func TestExtensionNode_commitCollapsedNode(t *testing.T) { _ = collapsedEn.setHash() collapsedEn.dirty = true - err := collapsedEn.commit(false, 0, db, db) + err := collapsedEn.commit(false, 0, 5, db, db) assert.Nil(t, err) encNode, _ := db.Get(hash) @@ -323,7 +323,7 @@ func TestExtensionNode_resolveCollapsed(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() _ = en.setHash() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) _, resolved := getBnAndCollapsedBn(en.marsh, en.hasher) err := collapsedEn.resolveCollapsed(0, db) @@ -409,7 +409,7 @@ func TestExtensionNode_tryGetCollapsedNode(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() _ = en.setHash() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) enKey := []byte{100} bnKey := []byte{2} @@ -500,7 +500,7 @@ func TestExtensionNode_insertCollapsedNode(t *testing.T) { node, _ := newLeafNode(key, []byte("dogs"), en.marsh, en.hasher) _ = en.setHash() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) dirty, newNode, _, err := collapsedEn.insert(node, db) assert.True(t, dirty) @@ -519,7 +519,7 @@ func TestExtensionNode_insertInStoredEnSameKey(t *testing.T) { key := append(enKey, []byte{11, 12}...) node, _ := newLeafNode(key, []byte("dogs"), en.marsh, en.hasher) - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) enHash := en.getHash() bn, _, _ := en.getNext(enKey, db) bnHash := bn.getHash() @@ -541,7 +541,7 @@ func TestExtensionNode_insertInStoredEnDifferentKey(t *testing.T) { nodeKey := []byte{11, 12} node, _ := newLeafNode(nodeKey, []byte("dogs"), bn.marsh, bn.hasher) - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) expectedHashes := [][]byte{en.getHash()} dirty, _, oldHashes, err := en.insert(node, db) @@ -623,7 +623,7 @@ func TestExtensionNode_deleteFromStoredEn(t *testing.T) { key = append(key, lnKey...) lnPathKey := key - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) bn, key, _ := en.getNext(key, db) ln, _, _ := bn.getNext(key, db) expectedHashes := [][]byte{ln.getHash(), bn.getHash(), en.getHash()} @@ -685,7 +685,7 @@ func TestExtensionNode_deleteCollapsedNode(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() _ = en.setHash() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) enKey := []byte{100} bnKey := []byte{2} @@ -814,7 +814,7 @@ func TestExtensionNode_getChildrenCollapsedEn(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() - _ = en.commit(true, 0, db, db) + _ = en.commit(true, 0, 5, db, db) children, err := collapsedEn.getChildren(db) assert.Nil(t, err) diff --git a/data/trie/factory/trieCreator.go b/data/trie/factory/trieCreator.go index 755e4b3301..72e5379737 100644 --- a/data/trie/factory/trieCreator.go +++ b/data/trie/factory/trieCreator.go @@ -55,7 +55,7 @@ func NewTrieFactory( } // Create creates a new trie -func (tc *trieCreator) Create(trieStorageCfg config.StorageConfig, pruningEnabled bool) (data.StorageManager, data.Trie, error) { +func (tc *trieCreator) Create(trieStorageCfg config.StorageConfig, pruningEnabled bool, maxTrieLevelInMem uint) (data.StorageManager, data.Trie, error) { trieStoragePath, mainDb := path.Split(tc.pathManager.PathForStatic(tc.shardId, trieStorageCfg.DB.FilePath)) dbConfig := factory.GetDBFromConfig(trieStorageCfg.DB) @@ -76,7 +76,7 @@ func (tc *trieCreator) Create(trieStorageCfg config.StorageConfig, pruningEnable return nil, nil, errNewTrie } - newTrie, err := trie.NewTrie(trieStorage, tc.marshalizer, tc.hasher) + newTrie, err := trie.NewTrie(trieStorage, tc.marshalizer, tc.hasher, maxTrieLevelInMem) if err != nil { return nil, nil, err } @@ -121,7 +121,7 @@ func (tc *trieCreator) Create(trieStorageCfg config.StorageConfig, pruningEnable return nil, nil, err } - newTrie, err := trie.NewTrie(trieStorage, tc.marshalizer, tc.hasher) + newTrie, err := trie.NewTrie(trieStorage, tc.marshalizer, tc.hasher, maxTrieLevelInMem) if err != nil { return nil, nil, err } diff --git a/data/trie/factory/trieCreator_test.go b/data/trie/factory/trieCreator_test.go index ac34d0cb24..8123cf4799 100644 --- a/data/trie/factory/trieCreator_test.go +++ b/data/trie/factory/trieCreator_test.go @@ -81,7 +81,8 @@ func TestTrieFactory_CreateNotSupportedCacheType(t *testing.T) { tf, _ := NewTrieFactory(args) trieStorageCfg := config.StorageConfig{} - _, tr, err := tf.Create(trieStorageCfg, false) + maxTrieLevelInMemory := uint(5) + _, tr, err := tf.Create(trieStorageCfg, false, maxTrieLevelInMemory) require.Nil(t, tr) require.Equal(t, storage.ErrNotSupportedCacheType, err) } @@ -93,7 +94,8 @@ func TestTrieFactory_CreateWithoutPrunningWork(t *testing.T) { tf, _ := NewTrieFactory(args) trieStorageCfg := createTrieStorageCfg() - _, tr, err := tf.Create(trieStorageCfg, false) + maxTrieLevelInMemory := uint(5) + _, tr, err := tf.Create(trieStorageCfg, false, maxTrieLevelInMemory) require.NotNil(t, tr) require.Nil(t, err) } @@ -105,7 +107,8 @@ func TestTrieFactory_CreateWithPrunningWrongDbType(t *testing.T) { tf, _ := NewTrieFactory(args) trieStorageCfg := createTrieStorageCfg() - _, tr, err := tf.Create(trieStorageCfg, true) + maxTrieLevelInMemory := uint(5) + _, tr, err := tf.Create(trieStorageCfg, true, maxTrieLevelInMemory) require.Nil(t, tr) require.Equal(t, storage.ErrNotSupportedDBType, err) } @@ -120,7 +123,8 @@ func TestTrieFactory_CreateInvalidCacheSize(t *testing.T) { tf, _ := NewTrieFactory(args) trieStorageCfg := createTrieStorageCfg() - _, tr, err := tf.Create(trieStorageCfg, true) + maxTrieLevelInMemory := uint(5) + _, tr, err := tf.Create(trieStorageCfg, true, maxTrieLevelInMemory) require.Nil(t, tr) require.Equal(t, data.ErrInvalidCacheSize, err) } @@ -136,7 +140,8 @@ func TestTrieFactory_CreateWithPRunningShouldWork(t *testing.T) { tf, _ := NewTrieFactory(args) trieStorageCfg := createTrieStorageCfg() - _, tr, err := tf.Create(trieStorageCfg, true) + maxTrieLevelInMemory := uint(5) + _, tr, err := tf.Create(trieStorageCfg, true, maxTrieLevelInMemory) require.NotNil(t, tr) require.Nil(t, err) } diff --git a/data/trie/interface.go b/data/trie/interface.go index 4d73f1ab91..2daceff064 100644 --- a/data/trie/interface.go +++ b/data/trie/interface.go @@ -21,7 +21,7 @@ type node interface { isPosCollapsed(pos int) bool isDirty() bool getEncodedNode() ([]byte, error) - commit(force bool, level byte, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error + commit(force bool, level byte, maxTrieLevelInMemory uint, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error resolveCollapsed(pos byte, db data.DBWriteCacher) error hashNode() ([]byte, error) hashChildren() error @@ -53,7 +53,7 @@ type atomicBuffer interface { } type snapshotNode interface { - commit(force bool, level byte, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error + commit(force bool, level byte, maxTrieLevelInMemory uint, originDb data.DBWriteCacher, targetDb data.DBWriteCacher) error } // RequestHandler defines the methods through which request to data can be made diff --git a/data/trie/leafNode.go b/data/trie/leafNode.go index de8fddf433..aae2f9e371 100644 --- a/data/trie/leafNode.go +++ b/data/trie/leafNode.go @@ -108,7 +108,7 @@ func (ln *leafNode) hashNode() ([]byte, error) { return encodeNodeAndGetHash(ln) } -func (ln *leafNode) commit(force bool, _ byte, _ data.DBWriteCacher, targetDb data.DBWriteCacher) error { +func (ln *leafNode) commit(force bool, _ byte, _ uint, _ data.DBWriteCacher, targetDb data.DBWriteCacher) error { err := ln.isEmptyOrNil() if err != nil { return fmt.Errorf("commit error %w", err) diff --git a/data/trie/leafNode_test.go b/data/trie/leafNode_test.go index a265fbf15a..bc704c70b7 100644 --- a/data/trie/leafNode_test.go +++ b/data/trie/leafNode_test.go @@ -154,7 +154,7 @@ func TestLeafNode_commit(t *testing.T) { hash, _ := encodeNodeAndGetHash(ln) _ = ln.setHash() - err := ln.commit(false, 0, db, db) + err := ln.commit(false, 0, 5, db, db) assert.Nil(t, err) encNode, _ := db.Get(hash) @@ -169,7 +169,7 @@ func TestLeafNode_commitEmptyNode(t *testing.T) { ln := &leafNode{} - err := ln.commit(false, 0, nil, nil) + err := ln.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrEmptyLeafNode)) } @@ -178,7 +178,7 @@ func TestLeafNode_commitNilNode(t *testing.T) { var ln *leafNode - err := ln.commit(false, 0, nil, nil) + err := ln.commit(false, 0, 5, nil, nil) assert.True(t, errors.Is(err, ErrNilLeafNode)) } @@ -352,7 +352,7 @@ func TestLeafNode_insertInStoredLnAtSameKey(t *testing.T) { db := mock.NewMemDbMock() ln := getLn(getTestMarshAndHasher()) node, _ := newLeafNode([]byte("dog"), []byte("dogs"), ln.marsh, ln.hasher) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) lnHash := ln.getHash() dirty, _, oldHashes, err := ln.insert(node, db) @@ -368,7 +368,7 @@ func TestLeafNode_insertInStoredLnAtDifferentKey(t *testing.T) { marsh, hasher := getTestMarshAndHasher() ln, _ := newLeafNode([]byte{1, 2, 3}, []byte("dog"), marsh, hasher) node, _ := newLeafNode([]byte{4, 5, 6}, []byte("dogs"), marsh, hasher) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) lnHash := ln.getHash() dirty, _, oldHashes, err := ln.insert(node, db) @@ -429,7 +429,7 @@ func TestLeafNode_deleteFromStoredLnAtSameKey(t *testing.T) { db := mock.NewMemDbMock() ln := getLn(getTestMarshAndHasher()) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) lnHash := ln.getHash() dirty, _, oldHashes, err := ln.delete([]byte("dog"), db) @@ -443,7 +443,7 @@ func TestLeafNode_deleteFromLnAtDifferentKey(t *testing.T) { db := mock.NewMemDbMock() ln := getLn(getTestMarshAndHasher()) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) wrongKey := []byte{1, 2, 3} dirty, _, oldHashes, err := ln.delete(wrongKey, db) diff --git a/data/trie/node.go b/data/trie/node.go index ae50e989d5..00ddce48b4 100644 --- a/data/trie/node.go +++ b/data/trie/node.go @@ -11,12 +11,11 @@ import ( ) const ( - nrOfChildren = 17 - firstByte = 0 - maxTrieLevelAfterCommit = 6 - hexTerminator = 16 - nibbleSize = 4 - nibbleMask = 0x0f + nrOfChildren = 17 + firstByte = 0 + hexTerminator = 16 + nibbleSize = 4 + nibbleMask = 0x0f ) type baseNode struct { diff --git a/data/trie/node_test.go b/data/trie/node_test.go index 55aed19b36..18c8a78d53 100644 --- a/data/trie/node_test.go +++ b/data/trie/node_test.go @@ -153,7 +153,7 @@ func TestNode_getNodeFromDBAndDecodeBranchNode(t *testing.T) { db := mock.NewMemDbMock() bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) encNode, _ := bn.marsh.Marshal(collapsedBn) encNode = append(encNode, branch) @@ -172,7 +172,7 @@ func TestNode_getNodeFromDBAndDecodeExtensionNode(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) encNode, _ := en.marsh.Marshal(collapsedEn) encNode = append(encNode, extension) @@ -191,7 +191,7 @@ func TestNode_getNodeFromDBAndDecodeLeafNode(t *testing.T) { db := mock.NewMemDbMock() ln := getLn(getTestMarshAndHasher()) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) encNode, _ := ln.marsh.Marshal(ln) encNode = append(encNode, leaf) @@ -211,7 +211,7 @@ func TestNode_resolveIfCollapsedBranchNode(t *testing.T) { db := mock.NewMemDbMock() bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) childPos := byte(2) - _ = bn.commit(false, 0, db, db) + _ = bn.commit(false, 0, 5, db, db) err := resolveIfCollapsed(collapsedBn, childPos, db) assert.Nil(t, err) @@ -223,7 +223,7 @@ func TestNode_resolveIfCollapsedExtensionNode(t *testing.T) { db := mock.NewMemDbMock() en, collapsedEn := getEnAndCollapsedEn() - _ = en.commit(false, 0, db, db) + _ = en.commit(false, 0, 5, db, db) err := resolveIfCollapsed(collapsedEn, 0, db) assert.Nil(t, err) @@ -235,7 +235,7 @@ func TestNode_resolveIfCollapsedLeafNode(t *testing.T) { db := mock.NewMemDbMock() ln := getLn(getTestMarshAndHasher()) - _ = ln.commit(false, 0, db, db) + _ = ln.commit(false, 0, 5, db, db) err := resolveIfCollapsed(ln, 0, db) assert.Nil(t, err) diff --git a/data/trie/patriciaMerkleTrie.go b/data/trie/patriciaMerkleTrie.go index 804f1d8b11..d237613d96 100644 --- a/data/trie/patriciaMerkleTrie.go +++ b/data/trie/patriciaMerkleTrie.go @@ -37,6 +37,8 @@ type patriciaMerkleTrie struct { oldHashes [][]byte oldRoot []byte newHashes data.ModifiedHashes + + maxTrieLevelInMemory uint } // NewTrie creates a new Patricia Merkle Trie @@ -44,6 +46,7 @@ func NewTrie( trieStorage data.StorageManager, msh marshal.Marshalizer, hsh hashing.Hasher, + maxTrieLevelInMemory uint, ) (*patriciaMerkleTrie, error) { if check.IfNil(trieStorage) { return nil, ErrNilTrieStorage @@ -54,14 +57,16 @@ func NewTrie( if check.IfNil(hsh) { return nil, ErrNilHasher } + log.Debug("created new trie", "max trie level in memory", maxTrieLevelInMemory) return &patriciaMerkleTrie{ - trieStorage: trieStorage, - marshalizer: msh, - hasher: hsh, - oldHashes: make([][]byte, 0), - oldRoot: make([]byte, 0), - newHashes: make(data.ModifiedHashes), + trieStorage: trieStorage, + marshalizer: msh, + hasher: hsh, + oldHashes: make([][]byte, 0), + oldRoot: make([]byte, 0), + newHashes: make(data.ModifiedHashes), + maxTrieLevelInMemory: maxTrieLevelInMemory, }, nil } @@ -208,7 +213,7 @@ func (tr *patriciaMerkleTrie) Commit() error { } } - err = tr.root.commit(false, 0, tr.trieStorage.Database(), tr.trieStorage.Database()) + err = tr.root.commit(false, 0, tr.maxTrieLevelInMemory, tr.trieStorage.Database(), tr.trieStorage.Database()) if err != nil { return err } @@ -277,6 +282,7 @@ func (tr *patriciaMerkleTrie) Recreate(root []byte) (data.Trie, error) { tr.trieStorage, tr.marshalizer, tr.hasher, + tr.maxTrieLevelInMemory, ) } @@ -423,6 +429,7 @@ func (tr *patriciaMerkleTrie) recreateFromDb(rootHash []byte) (data.Trie, error) tr.trieStorage, tr.marshalizer, tr.hasher, + tr.maxTrieLevelInMemory, ) if err != nil { return nil, err @@ -437,7 +444,7 @@ func (tr *patriciaMerkleTrie) recreateFromDb(rootHash []byte) (data.Trie, error) newTr.root = newRoot if db != tr.Database() { - err = newTr.root.commit(true, 0, db, tr.Database()) + err = newTr.root.commit(true, 0, tr.maxTrieLevelInMemory, db, tr.Database()) if err != nil { return nil, err } diff --git a/data/trie/patriciaMerkleTrie_test.go b/data/trie/patriciaMerkleTrie_test.go index 588d223690..e7a428e0a7 100644 --- a/data/trie/patriciaMerkleTrie_test.go +++ b/data/trie/patriciaMerkleTrie_test.go @@ -29,7 +29,7 @@ func emptyTrie() data.Trie { return tr } -func getDefaultTrieParameters() (data.StorageManager, marshal.Marshalizer, hashing.Hasher) { +func getDefaultTrieParameters() (data.StorageManager, marshal.Marshalizer, hashing.Hasher, uint) { db := mock.NewMemDbMock() marshalizer := &mock.ProtobufMarshalizerMock{} hasher := &mock.KeccakMock{} @@ -51,8 +51,9 @@ func getDefaultTrieParameters() (data.StorageManager, marshal.Marshalizer, hashi evictionWaitingList, _ := mock.NewEvictionWaitingList(100, mock.NewMemDbMock(), marshalizer) trieStorageManager, _ := trie.NewTrieStorageManager(db, marshalizer, hasher, cfg, evictionWaitingList, generalCfg) + maxTrieLevelInMemory := uint(5) - return trieStorageManager, marshalizer, hasher + return trieStorageManager, marshalizer, hasher, maxTrieLevelInMemory } func initTrieMultipleValues(nr int) (data.Trie, [][]byte) { @@ -81,8 +82,8 @@ func initTrie() data.Trie { func TestNewTrieWithNilTrieStorage(t *testing.T) { t.Parallel() - _, marshalizer, hasher := getDefaultTrieParameters() - tr, err := trie.NewTrie(nil, marshalizer, hasher) + _, marshalizer, hasher, maxTrieLevelInMemory := getDefaultTrieParameters() + tr, err := trie.NewTrie(nil, marshalizer, hasher, maxTrieLevelInMemory) assert.Nil(t, tr) assert.Equal(t, trie.ErrNilTrieStorage, err) @@ -91,8 +92,8 @@ func TestNewTrieWithNilTrieStorage(t *testing.T) { func TestNewTrieWithNilMarshalizer(t *testing.T) { t.Parallel() - trieStorage, _, hasher := getDefaultTrieParameters() - tr, err := trie.NewTrie(trieStorage, nil, hasher) + trieStorage, _, hasher, maxTrieLevelInMemory := getDefaultTrieParameters() + tr, err := trie.NewTrie(trieStorage, nil, hasher, maxTrieLevelInMemory) assert.Nil(t, tr) assert.Equal(t, trie.ErrNilMarshalizer, err) @@ -101,8 +102,8 @@ func TestNewTrieWithNilMarshalizer(t *testing.T) { func TestNewTrieWithNilHasher(t *testing.T) { t.Parallel() - trieStorage, marshalizer, _ := getDefaultTrieParameters() - tr, err := trie.NewTrie(trieStorage, marshalizer, nil) + trieStorage, marshalizer, _, maxTrieLevelInMemory := getDefaultTrieParameters() + tr, err := trie.NewTrie(trieStorage, marshalizer, nil, maxTrieLevelInMemory) assert.Nil(t, tr) assert.Equal(t, trie.ErrNilHasher, err) @@ -471,9 +472,9 @@ func TestPatriciaMerkleTrie_GetAllLeaves(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 3, len(leaves)) - assert.Equal(t, []byte("reindeer"), leaves[string([]byte("doe"))]) - assert.Equal(t, []byte("puppy"), leaves[string([]byte("dog"))]) - assert.Equal(t, []byte("cat"), leaves[string([]byte("ddog"))]) + assert.Equal(t, []byte("reindeer"), leaves["doe"]) + assert.Equal(t, []byte("puppy"), leaves["dog"]) + assert.Equal(t, []byte("cat"), leaves["ddog"]) } func BenchmarkPatriciaMerkleTree_Insert(b *testing.B) { diff --git a/data/trie/trieStorageManager.go b/data/trie/trieStorageManager.go index 8e4f8a5215..7a9609fd90 100644 --- a/data/trie/trieStorageManager.go +++ b/data/trie/trieStorageManager.go @@ -376,7 +376,8 @@ func (tsm *trieStorageManager) takeSnapshot(snapshot *snapshotsQueueEntry, msh m return } - err = newRoot.commit(true, 0, tsm.db, db) + maxTrieLevelInMemory := uint(5) + err = newRoot.commit(true, 0, maxTrieLevelInMemory, tsm.db, db) if err != nil { log.Error("trie storage manager: commit", "error", err.Error()) return diff --git a/data/trie/trieStorageManager_test.go b/data/trie/trieStorageManager_test.go index c530119829..b775d1dd61 100644 --- a/data/trie/trieStorageManager_test.go +++ b/data/trie/trieStorageManager_test.go @@ -82,7 +82,8 @@ func TestNewTrieStorageManagerWithExistingSnapshot(t *testing.T) { size := uint(100) evictionWaitList, _ := mock.NewEvictionWaitingList(size, mock.NewMemDbMock(), msh) trieStorage, _ := NewTrieStorageManager(db, msh, hsh, cfg, evictionWaitList, generalCfg) - tr, _ := NewTrie(trieStorage, msh, hsh) + maxTrieLevelInMemory := uint(5) + tr, _ := NewTrie(trieStorage, msh, hsh, maxTrieLevelInMemory) _ = tr.Update([]byte("doe"), []byte("reindeer")) _ = tr.Update([]byte("dog"), []byte("puppy")) diff --git a/epochStart/bootstrap/process.go b/epochStart/bootstrap/process.go index c906064cc6..434d050461 100644 --- a/epochStart/bootstrap/process.go +++ b/epochStart/bootstrap/process.go @@ -717,12 +717,13 @@ func (e *epochStartBootstrap) requestAndProcessForShard() error { func (e *epochStartBootstrap) syncUserAccountsState(rootHash []byte) error { argsUserAccountsSyncer := syncer.ArgsNewUserAccountsSyncer{ ArgsNewBaseAccountsSyncer: syncer.ArgsNewBaseAccountsSyncer{ - Hasher: e.hasher, - Marshalizer: e.marshalizer, - TrieStorageManager: e.trieStorageManagers[factory.UserAccountTrie], - RequestHandler: e.requestHandler, - WaitTime: trieSyncWaitTime, - Cacher: e.dataPool.TrieNodes(), + Hasher: e.hasher, + Marshalizer: e.marshalizer, + TrieStorageManager: e.trieStorageManagers[factory.UserAccountTrie], + RequestHandler: e.requestHandler, + WaitTime: trieSyncWaitTime, + Cacher: e.dataPool.TrieNodes(), + MaxTrieLevelInMemory: e.generalConfig.StateTriesConfig.MaxStateTrieLevelInMemory, }, ShardId: e.shardCoordinator.SelfId(), } @@ -755,7 +756,11 @@ func (e *epochStartBootstrap) createTriesForNewShardId(shardId uint32) error { return err } - userStorageManager, userAccountTrie, err := trieFactory.Create(e.generalConfig.AccountsTrieStorage, e.generalConfig.StateTriesConfig.AccountsStatePruningEnabled) + userStorageManager, userAccountTrie, err := trieFactory.Create( + e.generalConfig.AccountsTrieStorage, + e.generalConfig.StateTriesConfig.AccountsStatePruningEnabled, + e.generalConfig.StateTriesConfig.MaxStateTrieLevelInMemory, + ) if err != nil { return err } @@ -763,7 +768,11 @@ func (e *epochStartBootstrap) createTriesForNewShardId(shardId uint32) error { e.trieContainer.Replace([]byte(factory.UserAccountTrie), userAccountTrie) e.trieStorageManagers[factory.UserAccountTrie] = userStorageManager - peerStorageManager, peerAccountsTrie, err := trieFactory.Create(e.generalConfig.PeerAccountsTrieStorage, e.generalConfig.StateTriesConfig.PeerStatePruningEnabled) + peerStorageManager, peerAccountsTrie, err := trieFactory.Create( + e.generalConfig.PeerAccountsTrieStorage, + e.generalConfig.StateTriesConfig.PeerStatePruningEnabled, + e.generalConfig.StateTriesConfig.MaxPeerTrieLevelInMemory, + ) if err != nil { return err } @@ -777,12 +786,13 @@ func (e *epochStartBootstrap) createTriesForNewShardId(shardId uint32) error { func (e *epochStartBootstrap) syncPeerAccountsState(rootHash []byte) error { argsValidatorAccountsSyncer := syncer.ArgsNewValidatorAccountsSyncer{ ArgsNewBaseAccountsSyncer: syncer.ArgsNewBaseAccountsSyncer{ - Hasher: e.hasher, - Marshalizer: e.marshalizer, - TrieStorageManager: e.trieStorageManagers[factory.PeerAccountTrie], - RequestHandler: e.requestHandler, - WaitTime: trieSyncWaitTime, - Cacher: e.dataPool.TrieNodes(), + Hasher: e.hasher, + Marshalizer: e.marshalizer, + TrieStorageManager: e.trieStorageManagers[factory.PeerAccountTrie], + RequestHandler: e.requestHandler, + WaitTime: trieSyncWaitTime, + Cacher: e.dataPool.TrieNodes(), + MaxTrieLevelInMemory: e.generalConfig.StateTriesConfig.MaxPeerTrieLevelInMemory, }, } accountsDBSyncer, err := syncer.NewValidatorAccountsSyncer(argsValidatorAccountsSyncer) diff --git a/factory/triesComponents.go b/factory/triesComponents.go index 9937041f7f..a8a8c04a73 100644 --- a/factory/triesComponents.go +++ b/factory/triesComponents.go @@ -74,14 +74,22 @@ func (tcf *triesComponentsFactory) Create() (*TriesComponents, error) { } trieStorageManagers := make(map[string]data.StorageManager) - userStorageManager, userAccountTrie, err := trieFactoryObj.Create(tcf.config.AccountsTrieStorage, tcf.config.StateTriesConfig.AccountsStatePruningEnabled) + userStorageManager, userAccountTrie, err := trieFactoryObj.Create( + tcf.config.AccountsTrieStorage, + tcf.config.StateTriesConfig.AccountsStatePruningEnabled, + tcf.config.StateTriesConfig.MaxStateTrieLevelInMemory, + ) if err != nil { return nil, err } trieContainer.Put([]byte(trieFactory.UserAccountTrie), userAccountTrie) trieStorageManagers[trieFactory.UserAccountTrie] = userStorageManager - peerStorageManager, peerAccountsTrie, err := trieFactoryObj.Create(tcf.config.PeerAccountsTrieStorage, tcf.config.StateTriesConfig.PeerStatePruningEnabled) + peerStorageManager, peerAccountsTrie, err := trieFactoryObj.Create( + tcf.config.PeerAccountsTrieStorage, + tcf.config.StateTriesConfig.PeerStatePruningEnabled, + tcf.config.StateTriesConfig.MaxPeerTrieLevelInMemory, + ) if err != nil { return nil, err } diff --git a/integrationTests/consensus/testInitializer.go b/integrationTests/consensus/testInitializer.go index e291c4c1b8..6451d433d5 100644 --- a/integrationTests/consensus/testInitializer.go +++ b/integrationTests/consensus/testInitializer.go @@ -226,7 +226,8 @@ func createAccountsDB(marshalizer marshal.Marshalizer) state.AccountsAdapter { } trieStorage, _ := trie.NewTrieStorageManager(store, marshalizer, hasher, cfg, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, marsh, hasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, marsh, hasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, sha256.Sha256{}, marshalizer, &mock.AccountsFactoryStub{ CreateAccountCalled: func(address []byte) (wrapper state.AccountHandler, e error) { return state.NewUserAccount(address) diff --git a/integrationTests/longTests/storage/storage_test.go b/integrationTests/longTests/storage/storage_test.go index 618f51f848..d366384348 100644 --- a/integrationTests/longTests/storage/storage_test.go +++ b/integrationTests/longTests/storage/storage_test.go @@ -107,7 +107,8 @@ func TestWriteContinuouslyInTree(t *testing.T) { trieStorage, _ := trie.NewTrieStorageManagerWithoutPruning(store) - tr, _ := trie.NewTrie(trieStorage, &marshal.JsonMarshalizer{}, &blake2b.Blake2b{}) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, &marshal.JsonMarshalizer{}, &blake2b.Blake2b{}, maxTrieLevelInMemory) defer func() { _ = store.DestroyUnit() diff --git a/integrationTests/multiShard/endOfEpoch/startInEpoch/startInEpoch_test.go b/integrationTests/multiShard/endOfEpoch/startInEpoch/startInEpoch_test.go index b1a9ecc1ae..0b55911bde 100644 --- a/integrationTests/multiShard/endOfEpoch/startInEpoch/startInEpoch_test.go +++ b/integrationTests/multiShard/endOfEpoch/startInEpoch/startInEpoch_test.go @@ -304,14 +304,22 @@ func createTries( } trieStorageManagers := make(map[string]data.StorageManager) - userStorageManager, userAccountTrie, err := trieFactory.Create(config.AccountsTrieStorage, config.StateTriesConfig.AccountsStatePruningEnabled) + userStorageManager, userAccountTrie, err := trieFactory.Create( + config.AccountsTrieStorage, + config.StateTriesConfig.AccountsStatePruningEnabled, + config.StateTriesConfig.MaxStateTrieLevelInMemory, + ) if err != nil { return nil, nil, err } trieContainer.Put([]byte(triesFactory.UserAccountTrie), userAccountTrie) trieStorageManagers[triesFactory.UserAccountTrie] = userStorageManager - peerStorageManager, peerAccountsTrie, err := trieFactory.Create(config.PeerAccountsTrieStorage, config.StateTriesConfig.PeerStatePruningEnabled) + peerStorageManager, peerAccountsTrie, err := trieFactory.Create( + config.PeerAccountsTrieStorage, + config.StateTriesConfig.PeerStatePruningEnabled, + config.StateTriesConfig.MaxPeerTrieLevelInMemory, + ) if err != nil { return nil, nil, err } @@ -392,6 +400,8 @@ func getGeneralConfig() config.Config { CheckpointRoundsModulus: 100, AccountsStatePruningEnabled: false, PeerStatePruningEnabled: false, + MaxStateTrieLevelInMemory: 5, + MaxPeerTrieLevelInMemory: 5, }, TrieStorageManagerConfig: config.TrieStorageManagerConfig{ PruningBufferLen: 1000, diff --git a/integrationTests/multiShard/hardFork/hardFork_test.go b/integrationTests/multiShard/hardFork/hardFork_test.go index 63f19f1d12..2497a47bdb 100644 --- a/integrationTests/multiShard/hardFork/hardFork_test.go +++ b/integrationTests/multiShard/hardFork/hardFork_test.go @@ -238,6 +238,7 @@ func createHardForkExporter( MaxOpenFiles: 10, }, }, + MaxTrieLevelInMemory: uint(5), WhiteListHandler: node.WhiteListHandler, WhiteListerVerifiedTxs: node.WhiteListerVerifiedTxs, InterceptorsContainer: node.InterceptorsContainer, diff --git a/integrationTests/state/stateTrie/stateTrie_test.go b/integrationTests/state/stateTrie/stateTrie_test.go index feab0bbdea..33b1df6b74 100644 --- a/integrationTests/state/stateTrie/stateTrie_test.go +++ b/integrationTests/state/stateTrie/stateTrie_test.go @@ -252,7 +252,8 @@ func TestTrieDB_RecreateFromStorageShouldWork(t *testing.T) { ewl, _ := evictionWaitingList.NewEvictionWaitingList(evictionWaitListSize, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(store, integrationTests.TestMarshalizer, hasher, config.DBConfig{}, ewl, config.TrieStorageManagerConfig{}) - tr1, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, hasher) + maxTrieLevelInMemory := uint(5) + tr1, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, hasher, maxTrieLevelInMemory) key := hasher.Compute("key") value := hasher.Compute("value") @@ -312,7 +313,8 @@ func TestAccountsDB_CommitTwoOkAccountsWithRecreationFromStorageShouldWork(t *te ewl, _ := evictionWaitingList.NewEvictionWaitingList(100, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(mu, integrationTests.TestMarshalizer, integrationTests.TestHasher, config.DBConfig{}, ewl, config.TrieStorageManagerConfig{}) - tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory) adb, _ = state.NewAccountsDB(tr, integrationTests.TestHasher, integrationTests.TestMarshalizer, factory.NewAccountCreator()) //reloading a new trie to test if data is inside @@ -1019,7 +1021,8 @@ func createAccounts( ewl, _ := evictionWaitingList.NewEvictionWaitingList(evictionWaitListSize, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(store, integrationTests.TestMarshalizer, integrationTests.TestHasher, config.DBConfig{}, ewl, config.TrieStorageManagerConfig{}) - tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, integrationTests.TestHasher, integrationTests.TestMarshalizer, factory.NewAccountCreator()) addr := make([][]byte, nrOfAccounts) @@ -1098,7 +1101,8 @@ func TestTrieDbPruning_GetAccountAfterPruning(t *testing.T) { evictionWaitListSize := uint(100) ewl, _ := evictionWaitingList.NewEvictionWaitingList(evictionWaitListSize, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(memorydb.New(), integrationTests.TestMarshalizer, integrationTests.TestHasher, config.DBConfig{}, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, integrationTests.TestHasher, integrationTests.TestMarshalizer, factory.NewAccountCreator()) hexPubkeyConverter, _ := pubkeyConverter.NewHexPubkeyConverter(32) @@ -1139,7 +1143,8 @@ func TestAccountsDB_RecreateTrieInvalidatesDataTriesCache(t *testing.T) { evictionWaitListSize := uint(100) ewl, _ := evictionWaitingList.NewEvictionWaitingList(evictionWaitListSize, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(memorydb.New(), integrationTests.TestMarshalizer, integrationTests.TestHasher, config.DBConfig{}, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, integrationTests.TestHasher, integrationTests.TestMarshalizer, factory.NewAccountCreator()) hexAddressPubkeyConverter, _ := pubkeyConverter.NewHexPubkeyConverter(32) @@ -1192,7 +1197,8 @@ func TestTrieDbPruning_GetDataTrieTrackerAfterPruning(t *testing.T) { evictionWaitListSize := uint(100) ewl, _ := evictionWaitingList.NewEvictionWaitingList(evictionWaitListSize, memorydb.New(), integrationTests.TestMarshalizer) trieStorage, _ := trie.NewTrieStorageManager(memorydb.New(), integrationTests.TestMarshalizer, integrationTests.TestHasher, config.DBConfig{}, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, integrationTests.TestMarshalizer, integrationTests.TestHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, integrationTests.TestHasher, integrationTests.TestMarshalizer, factory.NewAccountCreator()) hexAddressPubkeyConverter, _ := pubkeyConverter.NewHexPubkeyConverter(32) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index db47bb20a2..c8d9fe3bf4 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -361,7 +361,8 @@ func CreateAccountsDB(accountType Type) (*state.AccountsDB, data.Trie, storage.S } trieStorage, _ := trie.NewTrieStorageManager(store, TestMarshalizer, TestHasher, cfg, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, TestMarshalizer, TestHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, TestMarshalizer, TestHasher, maxTrieLevelInMemory) accountFactory := getAccountFactory(accountType) adb, _ := state.NewAccountsDB(tr, sha256.Sha256{}, TestMarshalizer, accountFactory) @@ -734,7 +735,9 @@ func CreateNewDefaultTrie() data.Trie { MaxSnapshots: 2, } trieStorage, _ := trie.NewTrieStorageManager(CreateMemUnit(), TestMarshalizer, TestHasher, config.DBConfig{}, ewl, generalCfg) - tr, _ := trie.NewTrie(trieStorage, TestMarshalizer, TestHasher) + + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, TestMarshalizer, TestHasher, maxTrieLevelInMemory) return tr } diff --git a/integrationTests/vm/testInitializer.go b/integrationTests/vm/testInitializer.go index 19d5b4b824..6b4106d28a 100644 --- a/integrationTests/vm/testInitializer.go +++ b/integrationTests/vm/testInitializer.go @@ -118,7 +118,8 @@ func CreateInMemoryShardAccountsDB() *state.AccountsDB { generalCfg, ) - tr, _ := trie.NewTrie(trieStorage, marsh, testHasher) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorage, marsh, testHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, testHasher, marsh, &accountFactory{}) return adb diff --git a/update/factory/accountDBSyncerContainerFactory.go b/update/factory/accountDBSyncerContainerFactory.go index cc6c2112bb..8b16b0de5f 100644 --- a/update/factory/accountDBSyncerContainerFactory.go +++ b/update/factory/accountDBSyncerContainerFactory.go @@ -19,24 +19,26 @@ import ( // ArgsNewAccountsDBSyncersContainerFactory defines the arguments needed to create accounts DB syncers container type ArgsNewAccountsDBSyncersContainerFactory struct { - TrieCacher storage.Cacher - RequestHandler update.RequestHandler - ShardCoordinator sharding.Coordinator - Hasher hashing.Hasher - Marshalizer marshal.Marshalizer - TrieStorageManager data.StorageManager - WaitTime time.Duration + TrieCacher storage.Cacher + RequestHandler update.RequestHandler + ShardCoordinator sharding.Coordinator + Hasher hashing.Hasher + Marshalizer marshal.Marshalizer + TrieStorageManager data.StorageManager + WaitTime time.Duration + MaxTrieLevelInMemory uint } type accountDBSyncersContainerFactory struct { - trieCacher storage.Cacher - requestHandler update.RequestHandler - container update.AccountsDBSyncContainer - shardCoordinator sharding.Coordinator - hasher hashing.Hasher - marshalizer marshal.Marshalizer - waitTime time.Duration - trieStorageManager data.StorageManager + trieCacher storage.Cacher + requestHandler update.RequestHandler + container update.AccountsDBSyncContainer + shardCoordinator sharding.Coordinator + hasher hashing.Hasher + marshalizer marshal.Marshalizer + waitTime time.Duration + trieStorageManager data.StorageManager + maxTrieLevelinMemory uint } const minWaitTime = time.Second @@ -105,12 +107,13 @@ func (a *accountDBSyncersContainerFactory) Create() (update.AccountsDBSyncContai func (a *accountDBSyncersContainerFactory) createUserAccountsSyncer(shardId uint32) error { args := syncer.ArgsNewUserAccountsSyncer{ ArgsNewBaseAccountsSyncer: syncer.ArgsNewBaseAccountsSyncer{ - Hasher: a.hasher, - Marshalizer: a.marshalizer, - TrieStorageManager: a.trieStorageManager, - RequestHandler: a.requestHandler, - WaitTime: a.waitTime, - Cacher: a.trieCacher, + Hasher: a.hasher, + Marshalizer: a.marshalizer, + TrieStorageManager: a.trieStorageManager, + RequestHandler: a.requestHandler, + WaitTime: a.waitTime, + Cacher: a.trieCacher, + MaxTrieLevelInMemory: a.maxTrieLevelinMemory, }, ShardId: shardId, } @@ -126,12 +129,13 @@ func (a *accountDBSyncersContainerFactory) createUserAccountsSyncer(shardId uint func (a *accountDBSyncersContainerFactory) createValidatorAccountsSyncer(shardId uint32) error { args := syncer.ArgsNewValidatorAccountsSyncer{ ArgsNewBaseAccountsSyncer: syncer.ArgsNewBaseAccountsSyncer{ - Hasher: a.hasher, - Marshalizer: a.marshalizer, - TrieStorageManager: a.trieStorageManager, - RequestHandler: a.requestHandler, - WaitTime: a.waitTime, - Cacher: a.trieCacher, + Hasher: a.hasher, + Marshalizer: a.marshalizer, + TrieStorageManager: a.trieStorageManager, + RequestHandler: a.requestHandler, + WaitTime: a.waitTime, + Cacher: a.trieCacher, + MaxTrieLevelInMemory: a.maxTrieLevelinMemory, }, } accountSyncer, err := syncer.NewValidatorAccountsSyncer(args) diff --git a/update/factory/dataTrieFactory.go b/update/factory/dataTrieFactory.go index 8006eeabe3..c9eaa7f47a 100644 --- a/update/factory/dataTrieFactory.go +++ b/update/factory/dataTrieFactory.go @@ -20,18 +20,20 @@ import ( // ArgsNewDataTrieFactory is the argument structure for the new data trie factory type ArgsNewDataTrieFactory struct { - StorageConfig config.StorageConfig - SyncFolder string - Marshalizer marshal.Marshalizer - Hasher hashing.Hasher - ShardCoordinator sharding.Coordinator + StorageConfig config.StorageConfig + SyncFolder string + Marshalizer marshal.Marshalizer + Hasher hashing.Hasher + ShardCoordinator sharding.Coordinator + MaxTrieLevelInMemory uint } type dataTrieFactory struct { - shardCoordinator sharding.Coordinator - trieStorage data.StorageManager - marshalizer marshal.Marshalizer - hasher hashing.Hasher + shardCoordinator sharding.Coordinator + trieStorage data.StorageManager + marshalizer marshal.Marshalizer + hasher hashing.Hasher + maxTrieLevelInMemory uint } // NewDataTrieFactory creates a data trie factory @@ -105,7 +107,7 @@ func (d *dataTrieFactory) Create() (state.TriesHolder, error) { } func (d *dataTrieFactory) createAndAddOneTrie(shId uint32, accType genesis.Type, container state.TriesHolder) error { - dataTrie, err := trie.NewTrie(d.trieStorage, d.marshalizer, d.hasher) + dataTrie, err := trie.NewTrie(d.trieStorage, d.marshalizer, d.hasher, d.maxTrieLevelInMemory) if err != nil { return err } diff --git a/update/factory/exportHandlerFactory.go b/update/factory/exportHandlerFactory.go index a8cf1f2f3e..22e083ccf6 100644 --- a/update/factory/exportHandlerFactory.go +++ b/update/factory/exportHandlerFactory.go @@ -47,6 +47,7 @@ type ArgsExporter struct { ExportFolder string ExportTriesStorageConfig config.StorageConfig ExportStateStorageConfig config.StorageConfig + MaxTrieLevelInMemory uint WhiteListHandler process.WhiteListHandler WhiteListerVerifiedTxs process.WhiteListHandler InterceptorsContainer process.InterceptorsContainer @@ -79,6 +80,7 @@ type exportHandlerFactory struct { exportFolder string exportTriesStorageConfig config.StorageConfig exportStateStorageConfig config.StorageConfig + maxTrieLevelInMemory uint whiteListHandler process.WhiteListHandler whiteListerVerifiedTxs process.WhiteListHandler interceptorsContainer process.InterceptorsContainer @@ -248,11 +250,12 @@ func (e *exportHandlerFactory) Create() (update.ExportHandler, error) { } argsDataTrieFactory := ArgsNewDataTrieFactory{ - StorageConfig: e.exportTriesStorageConfig, - SyncFolder: e.exportFolder, - Marshalizer: e.marshalizer, - Hasher: e.hasher, - ShardCoordinator: e.shardCoordinator, + StorageConfig: e.exportTriesStorageConfig, + SyncFolder: e.exportFolder, + Marshalizer: e.marshalizer, + Hasher: e.hasher, + ShardCoordinator: e.shardCoordinator, + MaxTrieLevelInMemory: e.maxTrieLevelInMemory, } dataTriesContainerFactory, err := NewDataTrieFactory(argsDataTrieFactory) if err != nil { @@ -283,13 +286,14 @@ func (e *exportHandlerFactory) Create() (update.ExportHandler, error) { } argsAccountsSyncers := ArgsNewAccountsDBSyncersContainerFactory{ - TrieCacher: e.dataPool.TrieNodes(), - RequestHandler: e.requestHandler, - ShardCoordinator: e.shardCoordinator, - Hasher: e.hasher, - Marshalizer: e.marshalizer, - TrieStorageManager: dataTriesContainerFactory.TrieStorageManager(), - WaitTime: time.Minute, + TrieCacher: e.dataPool.TrieNodes(), + RequestHandler: e.requestHandler, + ShardCoordinator: e.shardCoordinator, + Hasher: e.hasher, + Marshalizer: e.marshalizer, + TrieStorageManager: dataTriesContainerFactory.TrieStorageManager(), + WaitTime: time.Minute, + MaxTrieLevelInMemory: e.maxTrieLevelInMemory, } accountsDBSyncerFactory, err := NewAccountsDBSContainerFactory(argsAccountsSyncers) if err != nil { From 4a5d5abc1f36847abbb6162560279b64844bfc3f Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 14:11:19 +0300 Subject: [PATCH 35/79] Fix some tests. --- .../vm/arwen/testdata/bad-misc/bad.c | 2 +- .../vm/arwen/testdata/bad-misc/bad.wasm | Bin 762 -> 765 bytes .../arwen/testdata/bad-misc/elrond/bigInt.h | 14 ++++++-- .../arwen/testdata/bad-misc/elrond/context.h | 23 +++++++++---- .../arwen/testdata/bad-misc/output/bad.wasm | Bin 0 -> 765 bytes .../arwen/testdata/erc20-c-03/elrond/bigInt.h | 14 ++++++-- .../testdata/erc20-c-03/elrond/context.h | 23 +++++++++---- .../erc20-c-03/output/wrc20_arwen.wasm | Bin 0 -> 6272 bytes .../arwen/testdata/erc20-c-03/wrc20_arwen.c | 32 +++++++++--------- .../testdata/erc20-c-03/wrc20_arwen.wasm | Bin 6240 -> 6272 bytes .../upgrades-parent/output/parent.wasm | Bin 0 -> 827 bytes .../arwen/testdata/upgrades-parent/parent.cpp | 10 +++--- .../testdata/upgrades-parent/parent.wasm | Bin 813 -> 827 bytes 13 files changed, 78 insertions(+), 40 deletions(-) create mode 100755 integrationTests/vm/arwen/testdata/bad-misc/output/bad.wasm create mode 100755 integrationTests/vm/arwen/testdata/erc20-c-03/output/wrc20_arwen.wasm create mode 100755 integrationTests/vm/arwen/testdata/upgrades-parent/output/parent.wasm diff --git a/integrationTests/vm/arwen/testdata/bad-misc/bad.c b/integrationTests/vm/arwen/testdata/bad-misc/bad.c index 50f3c1acb0..1425d540d2 100644 --- a/integrationTests/vm/arwen/testdata/bad-misc/bad.c +++ b/integrationTests/vm/arwen/testdata/bad-misc/bad.c @@ -86,7 +86,7 @@ void badWriteLog4() void badBigIntStorageStore1() { bigInt number = bigIntNew(100); - bigIntStorageStoreUnsigned("test", number + 42); + bigIntStorageStoreUnsigned("test", 32, number + 42); } i64 doStackoverflow(i64 a) { diff --git a/integrationTests/vm/arwen/testdata/bad-misc/bad.wasm b/integrationTests/vm/arwen/testdata/bad-misc/bad.wasm index e21b972ddb6cdd84d043a8c7f79bb88188383634..d3cb8d7a50401e8e3d4bb20faf0306b19e26a4eb 100755 GIT binary patch delta 66 zcmeyx`j=IOA+b1@k%57MQH?!;r5*?v5*UG)sji-}K7p|gNHEuLRPJPCoHcnZ<5n(N S2FC>*4Gj#A3X`*#CIA3v-4kU1 delta 63 zcmey%`ioVWA+b1@k%57MQI$P`r5*?v5*UG)sji-}K7p|gNHA?w>11S_F?k*1Rt{+f P#|0e?4GfcWnI-@LEXfjq diff --git a/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h b/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h index 2083e2ea12..9a6c2c413b 100644 --- a/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h +++ b/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h @@ -1,3 +1,6 @@ +#ifndef _BIGINT_H_ +#define _BIGINT_H_ + #include "types.h" typedef unsigned int bigInt; @@ -7,8 +10,8 @@ bigInt bigIntNew(long long value); void bigIntGetUnsignedArgument(int argumentIndex, bigInt argument); void bigIntGetSignedArgument(int argumentIndex, bigInt argument); -int bigIntStorageLoadUnsigned(byte *key, bigInt value); -int bigIntStorageStoreUnsigned(byte *key, bigInt value); +int bigIntStorageLoadUnsigned(byte *key, int keyLength, bigInt value); +int bigIntStorageStoreUnsigned(byte *key, int keyLength, bigInt value); void bigIntAdd(bigInt destination, bigInt op1, bigInt op2); void bigIntSub(bigInt destination, bigInt op1, bigInt op2); @@ -20,9 +23,14 @@ long long bigIntGetInt64(bigInt reference); void bigIntSetInt64(bigInt destination, long long value); void bigIntFinishUnsigned(bigInt reference); +void bigIntFinishSigned(bigInt reference); void bigIntGetCallValue(bigInt destination); -void bigIntGetExternalBalance(byte *address, bigInt result); +void bigIntgetExternalBalance(byte *address, bigInt result); int bigIntByteLength(bigInt reference); int bigIntGetUnsignedBytes(bigInt reference, byte *byte); +int bigIntGetSignedBytes(bigInt reference, byte *byte); void bigIntSetUnsignedBytes(bigInt destination, byte *byte, int byteLength); +void bigIntSetSignedBytes(bigInt destination, byte *byte, int byteLength); + +#endif diff --git a/integrationTests/vm/arwen/testdata/bad-misc/elrond/context.h b/integrationTests/vm/arwen/testdata/bad-misc/elrond/context.h index 1c2e1b34fa..8a982b7e17 100644 --- a/integrationTests/vm/arwen/testdata/bad-misc/elrond/context.h +++ b/integrationTests/vm/arwen/testdata/bad-misc/elrond/context.h @@ -1,3 +1,6 @@ +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + #include "types.h" void getOwner(byte *ownerAddress); @@ -10,7 +13,11 @@ long long getGasLeft(); void finish(byte *data, int length); void int64finish(long long value); void writeLog(byte *pointer, int length, byte *topicPtr, int numTopics); -void signalError(byte *messagePointer, int messageLength); +void asyncCall(byte *destination, byte *value, byte *data, int length); +void signalError(byte *message, int length); + +int executeOnSameContext(long long gas, byte *address, byte *value, byte *function, int functionLength, int numArguments, byte *argumentsLengths, byte *arguments); +int executeOnDestContext(long long gas, byte *address, byte *value, byte *function, int functionLength, int numArguments, byte *argumentsLengths, byte *arguments); // Blockchain-related functions long long getBlockTimestamp(); @@ -20,13 +27,17 @@ int getBlockHash(long long nonce, byte *hash); int getNumArguments(); int getArgument(int argumentIndex, byte *argument); long long int64getArgument(int argumentIndex); +int getArgumentLength(int argumentIndex); // Account-related functions void getExternalBalance(byte *address, byte *balance); -int transfer(long long gasLimit, byte *destination, byte *sender, byte *value, byte *data, int length); +int transferValue(byte *destination, byte *value, byte *data, int length); // Storage-related functions -int storageStore(byte *key, byte *data, int dataLength); -int storageLoad(byte *key, byte *data); -int int64storageStore(byte *key, long long value); -long long int64storageLoad(byte *key); +int storageLoadLength(byte *key, int keyLength); +int storageStore(byte *key, int keyLength, byte *data, int dataLength); +int storageLoad(byte *key, int keyLength, byte *data); +int int64storageStore(byte *key, int keyLength, long long value); +long long int64storageLoad(byte *key, int keyLength); + +#endif diff --git a/integrationTests/vm/arwen/testdata/bad-misc/output/bad.wasm b/integrationTests/vm/arwen/testdata/bad-misc/output/bad.wasm new file mode 100755 index 0000000000000000000000000000000000000000..d3cb8d7a50401e8e3d4bb20faf0306b19e26a4eb GIT binary patch literal 765 zcmaKq&2G~`6ot>VW5?~p=}?s}Dj|8rA}f-zV#RpT9|-{hAtY9Dn~`g1?897nS!+JDCr+3hhO%B>}Z}Mv+G)mu&tIwCq!hK1jBZyB=PgM#oE8f zwa0Rtq-O?L{jw9B9_O$-qi7P1q<{8FrU}}egJ87VG~b8AYdLSekClgLfYpa+8%)>v z*vzDl&axc9U6$MEF3aaw+f;k~YCOy1=!0wDJ9&7TX3<1qef5Xox)2b(7r6g6n>lQq zsPs@@e5L}d3vsWa%`YnX2>w5CslgUgq%sKb1)*kBL%2SL)Lk}JD^Mzc25dA{HJZc6 zm8eUJKW1Zn0&#b%juxK(8~jRlA$p(rb=}T07%x5eboJI%AL5%|eY)n~bQ?c4m*Wx$Y%-FzyP$Tiw&;0)ocMh|1ndSHkz&zBJ literal 0 HcmV?d00001 diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h index 2083e2ea12..9a6c2c413b 100644 --- a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h +++ b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h @@ -1,3 +1,6 @@ +#ifndef _BIGINT_H_ +#define _BIGINT_H_ + #include "types.h" typedef unsigned int bigInt; @@ -7,8 +10,8 @@ bigInt bigIntNew(long long value); void bigIntGetUnsignedArgument(int argumentIndex, bigInt argument); void bigIntGetSignedArgument(int argumentIndex, bigInt argument); -int bigIntStorageLoadUnsigned(byte *key, bigInt value); -int bigIntStorageStoreUnsigned(byte *key, bigInt value); +int bigIntStorageLoadUnsigned(byte *key, int keyLength, bigInt value); +int bigIntStorageStoreUnsigned(byte *key, int keyLength, bigInt value); void bigIntAdd(bigInt destination, bigInt op1, bigInt op2); void bigIntSub(bigInt destination, bigInt op1, bigInt op2); @@ -20,9 +23,14 @@ long long bigIntGetInt64(bigInt reference); void bigIntSetInt64(bigInt destination, long long value); void bigIntFinishUnsigned(bigInt reference); +void bigIntFinishSigned(bigInt reference); void bigIntGetCallValue(bigInt destination); -void bigIntGetExternalBalance(byte *address, bigInt result); +void bigIntgetExternalBalance(byte *address, bigInt result); int bigIntByteLength(bigInt reference); int bigIntGetUnsignedBytes(bigInt reference, byte *byte); +int bigIntGetSignedBytes(bigInt reference, byte *byte); void bigIntSetUnsignedBytes(bigInt destination, byte *byte, int byteLength); +void bigIntSetSignedBytes(bigInt destination, byte *byte, int byteLength); + +#endif diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/context.h b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/context.h index 1c2e1b34fa..8a982b7e17 100644 --- a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/context.h +++ b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/context.h @@ -1,3 +1,6 @@ +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + #include "types.h" void getOwner(byte *ownerAddress); @@ -10,7 +13,11 @@ long long getGasLeft(); void finish(byte *data, int length); void int64finish(long long value); void writeLog(byte *pointer, int length, byte *topicPtr, int numTopics); -void signalError(byte *messagePointer, int messageLength); +void asyncCall(byte *destination, byte *value, byte *data, int length); +void signalError(byte *message, int length); + +int executeOnSameContext(long long gas, byte *address, byte *value, byte *function, int functionLength, int numArguments, byte *argumentsLengths, byte *arguments); +int executeOnDestContext(long long gas, byte *address, byte *value, byte *function, int functionLength, int numArguments, byte *argumentsLengths, byte *arguments); // Blockchain-related functions long long getBlockTimestamp(); @@ -20,13 +27,17 @@ int getBlockHash(long long nonce, byte *hash); int getNumArguments(); int getArgument(int argumentIndex, byte *argument); long long int64getArgument(int argumentIndex); +int getArgumentLength(int argumentIndex); // Account-related functions void getExternalBalance(byte *address, byte *balance); -int transfer(long long gasLimit, byte *destination, byte *sender, byte *value, byte *data, int length); +int transferValue(byte *destination, byte *value, byte *data, int length); // Storage-related functions -int storageStore(byte *key, byte *data, int dataLength); -int storageLoad(byte *key, byte *data); -int int64storageStore(byte *key, long long value); -long long int64storageLoad(byte *key); +int storageLoadLength(byte *key, int keyLength); +int storageStore(byte *key, int keyLength, byte *data, int dataLength); +int storageLoad(byte *key, int keyLength, byte *data); +int int64storageStore(byte *key, int keyLength, long long value); +long long int64storageLoad(byte *key, int keyLength); + +#endif diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/output/wrc20_arwen.wasm b/integrationTests/vm/arwen/testdata/erc20-c-03/output/wrc20_arwen.wasm new file mode 100755 index 0000000000000000000000000000000000000000..f32cba19069607529b8318ec0d2c831226e1143d GIT binary patch literal 6272 zcmeI0TaX-88OOiwncbb)A!ZDlghY`Zd=RywU|~`oU+AQWN>Nbd3NOBF?{4opm7VTo zwkKg(hNMzw@2$YH>y?hKLv!=X)~sdflk^nBo5{pe{WU1*FILCQ1e(x)$PMK4BI! zuD3M5#O>>ImVEB>^F=hz>Maj`#S6aV2G@8a2xn zpc`COtJu}STE+E(5y|LiL0{$!U0$vFRmti|KDy^s?lNi9JfqphB4=pmT4$){N_$Ji zMU~;Gy*wJwRorTHes=T1?yze~%TY6PqqE(CUv&mueQ=X8L}Qzis&J+6^rz2vMdufn zz4FL6ny12^70{DrYvEkPgX*sJN=HlI?f!mnXTHPCMZavDF>Dw{TgDKxJ!jMnd;eIr z(9x4?uecSzI%-N5?FBNU5cq*J)Lk1M9vYQ%^S#cHTrgKtNv0~W}lOsSzPria$e`2Pvplt#1`9Ba%^Lxfud#16H#)UWGH!s zgqp9CGD=<}WtE&DwJCX>)UMVO)4mPhjfmTQ>1B1-X(oV z$!XGbC5=tZ@fDRUCw*AS3epTED@o@nSw-qnvYIqg$r{ouC2L8um8>J3r(`{8j*<7z=mkb{cR(`-wh=AyO9KcH<93PI|=@Fkl^oT z68zmlg1?<4_`8(^f4fNVx0?iidr0uNmjr*~B>0;k!QZz?@b_&J{M|-^zuQUh_Z<@a z-9duC?~>r}P7?fmj|6|;C&AwjNbvVV68zmog1;Y;;O}k{{Ot=V%EAL;NwI;S%q^@b z7`Zy~QbMo$buC>sN?Cm{OKtj)DYffEw$z~yZKa$(w3qVw&{68thg_);-35Mr8Mh1_ zzle+Q^z*og3iriDn7ubHLis&$5o_URaS@B;U|huNIS?1o9Palk5*qq73EqE0g7-rt zc)yJ(?@y56{r4nz zf06|6M@aB~lmzcj#T4zklO*Kr(Zt4Q#- zngoAqNbt9o1b^#D@VA}>e;Y{fw~+*Yn@I3CMuNZ1B>3Axg1@aK_}fN;zZ*#KcOwb@ zZX&_ob`t#UAi>|wB>2091b;h8@OLW-{&tbzZ#N14_K@IjFA4s}Lz>Y4t&ANWi_7)a zYlnNSohh!+RCvZTjJkPQabO5x(Y(x(BvxD- zUG`;MHW6MnKe^1_zX6qt2!u?S-8@qDY6!z&Pa*-U+jn6j@CXr9dy*jeMxQ~%TQRIF`9*rW0lgMY~h>m>G zIGRM}$x}L_WHO9IeJI&s593E$1U9={xD9W?%{jh&>Sh?T`hMrI#RCR_xx}O*)3Ffl z_`ntdR+OHsBG%%WHZ2Sa1+k|Z0ccSJ}<8R(JSrvbu3Jtx&{@GLr=QEWG{{fHovl#TmzcT2_C?{Lq zXa1M+zi_b4#5+N*@MCjX)%ON1uU6@GtCl}tIn58M68@YZa4W-s+iwNFm3-y125Mga zh_$rrSdQiS-n?OF)ae~^b-XVq`(AXd{(s%2s;TJH6IuG{bSr*0=@Z=^ObQ0^<^BXcxt S!COLSp^-_~`#=4=XW(y&+c`r3 literal 0 HcmV?d00001 diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.c b/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.c index d3660a98ff..910cbae690 100644 --- a/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.c +++ b/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.c @@ -92,11 +92,11 @@ void init() { // set total supply computeTotalSupplyKey(currentKey); - bigIntStorageStoreUnsigned(currentKey, totalSupply); + bigIntStorageStoreUnsigned(currentKey, 32, totalSupply); // sender balance <- total supply computeBalanceKey(currentKey, sender); - bigIntStorageStoreUnsigned(currentKey, totalSupply); + bigIntStorageStoreUnsigned(currentKey, 32, totalSupply); } // getter function: retrieves total token supply @@ -107,7 +107,7 @@ void totalSupply() { // load total supply from storage computeTotalSupplyKey(currentKey); bigInt totalSupply = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, totalSupply); + bigIntStorageLoadUnsigned(currentKey, 32, totalSupply); // return total supply as big int bigIntFinishUnsigned(totalSupply); @@ -124,7 +124,7 @@ void balanceOf() { // load balance computeBalanceKey(currentKey, caller); bigInt balance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, balance); + bigIntStorageLoadUnsigned(currentKey, 32, balance); // return balance as big int bigIntFinishUnsigned(balance); @@ -144,7 +144,7 @@ void allowance() { // get allowance computeAllowanceKey(currentKey, sender, recipient); bigInt allowance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, allowance); + bigIntStorageLoadUnsigned(currentKey, 32, allowance); // return allowance as big int bigIntFinishUnsigned(allowance); @@ -172,7 +172,7 @@ void transferToken() { // load sender balance computeBalanceKey(currentKey, sender); bigInt senderBalance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, senderBalance); + bigIntStorageLoadUnsigned(currentKey, 32, senderBalance); // check if enough funds if (bigIntCmp(amount, senderBalance) > 0) { @@ -182,14 +182,14 @@ void transferToken() { // update sender balance bigIntSub(senderBalance, senderBalance, amount); - bigIntStorageStoreUnsigned(currentKey, senderBalance); + bigIntStorageStoreUnsigned(currentKey, 32, senderBalance); // load & update receiver balance computeBalanceKey(currentKey, recipient); bigInt receiverBalance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, receiverBalance); + bigIntStorageLoadUnsigned(currentKey, 32, receiverBalance); bigIntAdd(receiverBalance, receiverBalance, amount); - bigIntStorageStoreUnsigned(currentKey, receiverBalance); + bigIntStorageStoreUnsigned(currentKey, 32, receiverBalance); // log operation saveLogWith3Topics(transferEvent, sender, recipient, amount); @@ -217,7 +217,7 @@ void approve() { // store allowance computeAllowanceKey(currentKey, sender, recipient); - bigIntStorageStoreUnsigned(currentKey, amount); + bigIntStorageStoreUnsigned(currentKey, 32, amount); // log operation saveLogWith3Topics(approveEvent, sender, recipient, amount); @@ -249,7 +249,7 @@ void transferFrom() { // load allowance computeAllowanceKey(currentKey, sender, caller); bigInt allowance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, allowance); + bigIntStorageLoadUnsigned(currentKey, 32, allowance); // amount should not exceed allowance if (bigIntCmp(amount, allowance) > 0) { @@ -259,12 +259,12 @@ void transferFrom() { // update allowance bigIntSub(allowance, allowance, amount); - bigIntStorageStoreUnsigned(currentKey, allowance); + bigIntStorageStoreUnsigned(currentKey, 32, allowance); // load sender balance computeBalanceKey(currentKey, sender); bigInt senderBalance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, senderBalance); + bigIntStorageLoadUnsigned(currentKey, 32, senderBalance); // check if enough funds if (bigIntCmp(amount, senderBalance) > 0) { @@ -274,14 +274,14 @@ void transferFrom() { // update sender balance bigIntSub(senderBalance, senderBalance, amount); - bigIntStorageStoreUnsigned(currentKey, senderBalance); + bigIntStorageStoreUnsigned(currentKey, 32, senderBalance); // load & update receiver balance computeBalanceKey(currentKey, recipient); bigInt receiverBalance = bigIntNew(0); - bigIntStorageLoadUnsigned(currentKey, receiverBalance); + bigIntStorageLoadUnsigned(currentKey, 32, receiverBalance); bigIntAdd(receiverBalance, receiverBalance, amount); - bigIntStorageStoreUnsigned(currentKey, receiverBalance); + bigIntStorageStoreUnsigned(currentKey, 32, receiverBalance); // log operation saveLogWith3Topics(transferEvent, sender, recipient, amount); diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.wasm b/integrationTests/vm/arwen/testdata/erc20-c-03/wrc20_arwen.wasm index 1331b5435d91f03b2046fe2b937e6ee5f8ff69d7..f32cba19069607529b8318ec0d2c831226e1143d 100755 GIT binary patch delta 241 zcmaE0&|tVhlaY~OvKFH}ko01_#57lZvmBEaC*z~ZKD?2WtN3{*ujh7Ra#Wc7k$Ww# zqk;m1KvzRU1A`Rz;>jy{IzSSJyi$zIHv8~$Gs1Z5C$AEWoP3(k8Ya-cS&=^gEL|wz z!Ui;jQJ`z`I$p8K=LIH%)P#sCgQ#**6~^~Ky{Gt)EOLC%F?ph(1Y_^ynL;-~stN^^ XCr=etL^kGvFxVJ;hHowxeaQp>hs;IK delta 174 zcmZoLd|-syhku{@?}125Ravum62)ke!*FjBZUPf-{4<7 zxmLhs@;PCt$#(@NPc9Nvo;+Pph4C#=%c;p7LMn`nlh+E}1gcSi$0Z3GoNX+^!=p;a5TN> zQxs?hvk@$b*22zqKTmq5)*xtokWLF5E8!jof}2Fur8?DWE5`CP#bt4Pz}H$Sg!@)_ zQ85S~+tg<1R2UQ_|14(#!Y5W5lU_>o_Wi9`oOMx}8vB9s^LRV3xQ;ssZL8{kt@8VO#44=AatG?t490_7=6W1&w@ vKkdu4TIi&D)s{H?KCWtnFYNw|em{9|ML_TQLDaSXclF-^=wm-{-~hh>@nzP@ literal 0 HcmV?d00001 diff --git a/integrationTests/vm/arwen/testdata/upgrades-parent/parent.cpp b/integrationTests/vm/arwen/testdata/upgrades-parent/parent.cpp index f2b6a47b42..33f7d63a95 100644 --- a/integrationTests/vm/arwen/testdata/upgrades-parent/parent.cpp +++ b/integrationTests/vm/arwen/testdata/upgrades-parent/parent.cpp @@ -10,8 +10,8 @@ extern "C" int getNumArguments(); int getArgument(int argumentIndex, byte *argument); int getArgumentLength(int argumentIndex); - int storageStore(byte *key, byte *data, int dataLength); - int storageLoad(byte *key, byte *data); + int storageStore(byte *key, int keyLength, byte *data, int dataLength); + int storageLoad(byte *key, int keyLength, byte *data); void signalError(byte *message, int length); void asyncCall(byte *destination, byte *value, byte *data, int length); } @@ -47,7 +47,7 @@ extern "C" void getUltimateAnswer() extern "C" void getChildAddress() { byte childAddress[32]; - storageLoad((byte *)childContractAddressKey, childAddress); + storageLoad((byte *)childContractAddressKey, 32, childAddress); finish(childAddress, 32); } @@ -58,7 +58,7 @@ extern "C" void createChild() getArgument(0, code); byte childAddress[32]; createContract(nullptr, code, codeLength, childAddress, 0, nullptr, nullptr); - storageStore((byte *)childContractAddressKey, childAddress, 32); + storageStore((byte *)childContractAddressKey, 32, childAddress, 32); } extern "C" void upgradeChild() @@ -68,7 +68,7 @@ extern "C" void upgradeChild() getArgument(0, code); byte childAddress[32]; - storageLoad((byte *)childContractAddressKey, childAddress); + storageLoad((byte *)childContractAddressKey, 32, childAddress); // "upgradeContract@code@0100" int dataLength = 15 + 1 + codeLength + 1 + 4; diff --git a/integrationTests/vm/arwen/testdata/upgrades-parent/parent.wasm b/integrationTests/vm/arwen/testdata/upgrades-parent/parent.wasm index a8c326488a6c9830324779ee47d3f2f3e8472292..5bb0d92a58c7c559a06acff70b15d8c2326f9dbe 100755 GIT binary patch delta 204 zcmZ3>wwuj_A+b1@k%57M(ULQPv5p~uxxT)hu|9#RzMdh05y}Gc*@40!0A#Y%Pt?hE zU|~+pE8|NpN=+Ub1syP7VV* zGb;-R5KO$8#=no5g^R&SSD*n17`W{w`!UKgIVw!fW|U_xW@Mhkq&|5IqoI_ef&zo1 afWnQv#VonYN8#5~lI}l8K zn5MIXnT3nNNmrl&2pG6+7#Zu8!AwVmY$XO22$MmBX-NlAdU7eFJaZu<^JE?-^~w7f U4JUtO6leTBnUl$Fav;+y09^JsbpQYW From e03a9fa21264b93a09ef2588d60db834be5912a7 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Wed, 13 May 2020 14:58:16 +0300 Subject: [PATCH 36/79] fix after merge --- go.sum | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go.sum b/go.sum index 4f52f7a3d4..c143ca7071 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.16 h1:JZurmIDNlKK3W8kCClQ1DNAl7j4sLfGgc9yniVjisGE= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.16/go.mod h1:Ny/uDh27JLWdFaCTp+Ek4hw5Ory/sTsjA3QWmP//mpU= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.17 h1:+kbE3wwOY1BiPRlH0AGQQJ77anpevogCDsTdFNc3OdU= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.17/go.mod h1:cyBSzwbWSGqXJz5excz9PhF4FOhWvS3EFggiFReHsdU= github.com/ElrondNetwork/big-int-util v0.0.5 h1:e/9kK++9ZH/SdIYqLSUPRFYrDZmDWDgff3/7SCydq5I= github.com/ElrondNetwork/big-int-util v0.0.5/go.mod h1:96viBvoTXLjZOhEvE0D+QnAwg1IJLPAK6GVHMbC7Aw4= github.com/ElrondNetwork/concurrent-map v0.1.2 h1:mr2sVF2IPDsJO8DNGzCUiNQOJcadHuIRVZn+QFnCBlE= @@ -20,7 +20,7 @@ github.com/ElrondNetwork/elrond-vm-common v0.1.9/go.mod h1:ZakxPST/Wt8umnRtA9gob github.com/ElrondNetwork/elrond-vm-common v0.1.19 h1:mRO768HtMyXY23pvG18DonKVEIlNvXxoyKP94S9fb2A= github.com/ElrondNetwork/elrond-vm-common v0.1.19/go.mod h1:ZakxPST/Wt8umnRtA9gobcy3Dw2bywxwkC54P5VhO9g= github.com/ElrondNetwork/elrond-vm-util v0.1.1/go.mod h1:02LPKFh/Z5rbejgW2dazwjWGnsniuLOhRM2JjaOA3Mg= -github.com/ElrondNetwork/elrond-vm-util v0.2.3/go.mod h1:tLiuKpnQB5IrcMtZvwAJqo2WwUMzXX024SsEsTlmNL4= +github.com/ElrondNetwork/elrond-vm-util v0.2.5/go.mod h1:tLiuKpnQB5IrcMtZvwAJqo2WwUMzXX024SsEsTlmNL4= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= From e9a9332685eeaa095af477f5a25f2533996d5362 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 15:05:55 +0300 Subject: [PATCH 37/79] add missing unit tests for branchNode --- data/trie/branchNode_test.go | 126 +++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/data/trie/branchNode_test.go b/data/trie/branchNode_test.go index 3fb2777eb5..7b586fd4f1 100644 --- a/data/trie/branchNode_test.go +++ b/data/trie/branchNode_test.go @@ -1,6 +1,7 @@ package trie import ( + "bytes" "encoding/hex" "errors" "fmt" @@ -1209,3 +1210,128 @@ func BenchmarkMarshallNodeJson(b *testing.B) { _, _ = marsh.Marshal(bn) } } + +func TestBranchNode_newBranchNodeNilMarshalizerShouldErr(t *testing.T) { + t.Parallel() + + bn, err := newBranchNode(nil, mock.HasherMock{}) + assert.Nil(t, bn) + assert.Equal(t, ErrNilMarshalizer, err) +} + +func TestBranchNode_newBranchNodeNilHasherShouldErr(t *testing.T) { + t.Parallel() + + bn, err := newBranchNode(&mock.MarshalizerMock{}, nil) + assert.Nil(t, bn) + assert.Equal(t, ErrNilHasher, err) +} + +func TestBranchNode_newBranchNodeOkVals(t *testing.T) { + t.Parallel() + + var children [nrOfChildren]node + marsh, hasher := getTestMarshAndHasher() + bn, err := newBranchNode(marsh, hasher) + + assert.Nil(t, err) + assert.Equal(t, make([][]byte, nrOfChildren), bn.EncodedChildren) + assert.Equal(t, children, bn.children) + assert.Equal(t, marsh, bn.marsh) + assert.Equal(t, hasher, bn.hasher) + assert.True(t, bn.dirty) +} + +func TestBranchNode_getMarshalizer(t *testing.T) { + t.Parallel() + + expectedMarsh := &mock.MarshalizerMock{} + bn := &branchNode{ + baseNode: &baseNode{ + marsh: expectedMarsh, + }, + } + + marsh := bn.getMarshalizer() + assert.Equal(t, expectedMarsh, marsh) +} + +func TestBranchNode_setRootHashCollapsedChildren(t *testing.T) { + t.Parallel() + + marsh, hasher := getTestMarshAndHasher() + bn := &branchNode{ + baseNode: &baseNode{ + marsh: marsh, + hasher: hasher, + }, + } + + _, collapsedBn := getBnAndCollapsedBn(marsh, hasher) + _, collapsedEn := getEnAndCollapsedEn() + collapsedLn := getLn(marsh, hasher) + + bn.children[0] = collapsedBn + bn.children[1] = collapsedEn + bn.children[2] = collapsedLn + + err := bn.setRootHash() + assert.Nil(t, err) +} + +func TestBranchNode_commitCollapsesTrieIfMaxTrieLevelInMemoryIsReached(t *testing.T) { + t.Parallel() + + bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) + _ = collapsedBn.setRootHash() + + err := bn.commit(true, 0, 1, mock.NewMemDbMock(), mock.NewMemDbMock()) + assert.Nil(t, err) + + assert.Equal(t, collapsedBn.EncodedChildren, bn.EncodedChildren) + assert.Equal(t, collapsedBn.children, bn.children) + assert.Equal(t, collapsedBn.hash, bn.hash) +} + +func TestBranchNode_reduceNodeBnChild(t *testing.T) { + t.Parallel() + + marsh, hasher := getTestMarshAndHasher() + en, _ := getEnAndCollapsedEn() + pos := 5 + expectedNode, _ := newExtensionNode([]byte{byte(pos)}, en.child, marsh, hasher) + + newNode, err := en.child.reduceNode(pos) + assert.Nil(t, err) + assert.Equal(t, expectedNode, newNode) +} + +func TestBranchNode_printShouldNotPanicEvenIfNodeIsCollapsed(t *testing.T) { + t.Parallel() + + bnWriter := bytes.NewBuffer(make([]byte, 0)) + collapsedBnWriter := bytes.NewBuffer(make([]byte, 0)) + + db := mock.NewMemDbMock() + bn, collapsedBn := getBnAndCollapsedBn(getTestMarshAndHasher()) + _ = bn.commit(true, 0, 5, db, db) + _ = collapsedBn.commit(true, 0, 5, db, db) + + bn.print(bnWriter, 0, db) + collapsedBn.print(collapsedBnWriter, 0, db) + + assert.Equal(t, bnWriter.Bytes(), collapsedBnWriter.Bytes()) +} + +func TestBranchNode_getDirtyHashesFromNotDirtyNode(t *testing.T) { + t.Parallel() + + db := mock.NewMemDbMock() + bn, _ := getBnAndCollapsedBn(getTestMarshAndHasher()) + _ = bn.commit(true, 0, 5, db, db) + dirtyHashes := make(data.ModifiedHashes) + + err := bn.getDirtyHashes(dirtyHashes) + assert.Nil(t, err) + assert.Equal(t, 0, len(dirtyHashes)) +} From b9606b38b66b6ffd0246efa2d7843fa8a38989c7 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 15:34:01 +0300 Subject: [PATCH 38/79] add missing unit tests for extensionNode --- data/trie/branchNode_test.go | 2 +- data/trie/extensionNode.go | 20 ------- data/trie/extensionNode_test.go | 93 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/data/trie/branchNode_test.go b/data/trie/branchNode_test.go index 7b586fd4f1..7a6bb8a528 100644 --- a/data/trie/branchNode_test.go +++ b/data/trie/branchNode_test.go @@ -1323,7 +1323,7 @@ func TestBranchNode_printShouldNotPanicEvenIfNodeIsCollapsed(t *testing.T) { assert.Equal(t, bnWriter.Bytes(), collapsedBnWriter.Bytes()) } -func TestBranchNode_getDirtyHashesFromNotDirtyNode(t *testing.T) { +func TestBranchNode_getDirtyHashesFromCleanNode(t *testing.T) { t.Parallel() db := mock.NewMemDbMock() diff --git a/data/trie/extensionNode.go b/data/trie/extensionNode.go index ff2b86dd88..5726892acd 100644 --- a/data/trie/extensionNode.go +++ b/data/trie/extensionNode.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "sync" "github.com/ElrondNetwork/elrond-go/core/check" @@ -16,25 +15,6 @@ import ( var _ = node(&extensionNode{}) -// Save saves the serialized data of an extension node into a stream through protobuf -func (en *extensionNode) Save(w io.Writer) error { - b, err := en.Marshal() - if err != nil { - return err - } - _, err = w.Write(b) - return err -} - -// Load loads the data from the stream into an extension node object through protobuf -func (en *extensionNode) Load(r io.Reader) error { - b, err := ioutil.ReadAll(r) - if err != nil { - return err - } - return en.Unmarshal(b) -} - func newExtensionNode(key []byte, child node, marshalizer marshal.Marshalizer, hasher hashing.Hasher) (*extensionNode, error) { if check.IfNil(marshalizer) { return nil, ErrNilMarshalizer diff --git a/data/trie/extensionNode_test.go b/data/trie/extensionNode_test.go index 995995014f..86fda1ebcf 100644 --- a/data/trie/extensionNode_test.go +++ b/data/trie/extensionNode_test.go @@ -1,12 +1,15 @@ package trie import ( + "bytes" "encoding/hex" "errors" "fmt" "reflect" "testing" + "github.com/ElrondNetwork/elrond-go/data" + "github.com/ElrondNetwork/elrond-go/data/mock" "github.com/ElrondNetwork/elrond-go/storage/lrucache" "github.com/stretchr/testify/assert" @@ -934,3 +937,93 @@ func getExtensionNodeContents(en *extensionNode) string { return str } + +func TestExtensionNode_newExtensionNodeNilMarshalizerShouldErr(t *testing.T) { + t.Parallel() + + en, err := newExtensionNode([]byte("key"), &branchNode{}, nil, mock.HasherMock{}) + assert.Nil(t, en) + assert.Equal(t, ErrNilMarshalizer, err) +} + +func TestExtensionNode_newExtensionNodeNilHasherShouldErr(t *testing.T) { + t.Parallel() + + en, err := newExtensionNode([]byte("key"), &branchNode{}, &mock.MarshalizerMock{}, nil) + assert.Nil(t, en) + assert.Equal(t, ErrNilHasher, err) +} + +func TestExtensionNode_newExtensionNodeOkVals(t *testing.T) { + t.Parallel() + + marsh, hasher := getTestMarshAndHasher() + key := []byte("key") + child := &branchNode{} + en, err := newExtensionNode(key, child, marsh, hasher) + + assert.Nil(t, err) + assert.Equal(t, key, en.Key) + assert.Nil(t, en.EncodedChild) + assert.Equal(t, child, en.child) + assert.Equal(t, hasher, en.hasher) + assert.Equal(t, marsh, en.marsh) + assert.True(t, en.dirty) +} + +func TestExtensionNode_getMarshalizer(t *testing.T) { + t.Parallel() + + marsh, _ := getTestMarshAndHasher() + en := &extensionNode{ + baseNode: &baseNode{ + marsh: marsh, + }, + } + + assert.Equal(t, marsh, en.getMarshalizer()) +} + +func TestExtensionNode_commitCollapsesTrieIfMaxTrieLevelInMemoryIsReached(t *testing.T) { + t.Parallel() + + en, collapsedEn := getEnAndCollapsedEn() + _ = collapsedEn.setRootHash() + + err := en.commit(true, 0, 1, mock.NewMemDbMock(), mock.NewMemDbMock()) + assert.Nil(t, err) + + assert.Equal(t, collapsedEn.EncodedChild, en.EncodedChild) + assert.Equal(t, collapsedEn.child, en.child) + assert.Equal(t, collapsedEn.hash, en.hash) +} + +func TestExtensionNode_printShouldNotPanicEvenIfNodeIsCollapsed(t *testing.T) { + t.Parallel() + + enWriter := bytes.NewBuffer(make([]byte, 0)) + collapsedEnWriter := bytes.NewBuffer(make([]byte, 0)) + + db := mock.NewMemDbMock() + en, collapsedEn := getEnAndCollapsedEn() + _ = en.commit(true, 0, 5, db, db) + _ = collapsedEn.commit(true, 0, 5, db, db) + + en.print(enWriter, 0, db) + collapsedEn.print(collapsedEnWriter, 0, db) + + assert.Equal(t, enWriter.Bytes(), collapsedEnWriter.Bytes()) +} + +func TestExtensionNode_getDirtyHashesFromCleanNode(t *testing.T) { + t.Parallel() + + db := mock.NewMemDbMock() + en, _ := getEnAndCollapsedEn() + _ = en.commit(true, 0, 5, db, db) + dirtyHashes := make(data.ModifiedHashes) + + err := en.getDirtyHashes(dirtyHashes) + assert.Nil(t, err) + assert.Equal(t, 0, len(dirtyHashes)) +} From 3f5bf5648fb718d873fbf5ff63fe1f2485a46e4a Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 15:47:16 +0300 Subject: [PATCH 39/79] add missing unit tests for interceptedNode --- data/trie/interceptedNode_test.go | 73 +++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/data/trie/interceptedNode_test.go b/data/trie/interceptedNode_test.go index eee6239a72..2bf221802a 100644 --- a/data/trie/interceptedNode_test.go +++ b/data/trie/interceptedNode_test.go @@ -1,8 +1,10 @@ package trie_test import ( + "math/big" "testing" + "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/mock" "github.com/ElrondNetwork/elrond-go/data/trie" @@ -46,7 +48,7 @@ func TestNewInterceptedTrieNode_EmptyBufferShouldFail(t *testing.T) { _, marsh, hasher := getDefaultInterceptedTrieNodeParameters() interceptedNode, err := trie.NewInterceptedTrieNode([]byte{}, marsh, hasher) - assert.Nil(t, interceptedNode) + assert.True(t, check.IfNil(interceptedNode)) assert.Equal(t, trie.ErrValueTooShort, err) } @@ -55,7 +57,7 @@ func TestNewInterceptedTrieNode_NilMarshalizerShouldFail(t *testing.T) { buff, _, hasher := getDefaultInterceptedTrieNodeParameters() interceptedNode, err := trie.NewInterceptedTrieNode(buff, nil, hasher) - assert.Nil(t, interceptedNode) + assert.True(t, check.IfNil(interceptedNode)) assert.Equal(t, trie.ErrNilMarshalizer, err) } @@ -64,7 +66,7 @@ func TestNewInterceptedTrieNode_NilHasherShouldFail(t *testing.T) { buff, marsh, _ := getDefaultInterceptedTrieNodeParameters() interceptedNode, err := trie.NewInterceptedTrieNode(buff, marsh, nil) - assert.Nil(t, interceptedNode) + assert.True(t, check.IfNil(interceptedNode)) assert.Equal(t, trie.ErrNilHasher, err) } @@ -72,7 +74,7 @@ func TestNewInterceptedTrieNode_OkParametersShouldWork(t *testing.T) { t.Parallel() interceptedNode, err := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) - assert.NotNil(t, interceptedNode) + assert.False(t, check.IfNil(interceptedNode)) assert.Nil(t, err) } @@ -106,3 +108,66 @@ func TestInterceptedTrieNode_EncodedNode(t *testing.T) { encNode := interceptedNode.EncodedNode() assert.Equal(t, nodes[0], encNode) } + +func TestInterceptedTrieNode_IsForCurrentShard(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.True(t, interceptedNode.IsForCurrentShard()) +} + +func TestInterceptedTrieNode_Type(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.Equal(t, "intercepted trie node", interceptedNode.Type()) +} + +func TestInterceptedTrieNode_String(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.NotEqual(t, 0, interceptedNode.String()) +} + +func TestInterceptedTrieNode_SenderShardId(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.NotEqual(t, 0, interceptedNode.SenderShardId()) +} + +func TestInterceptedTrieNode_ReceiverShardId(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.NotEqual(t, 0, interceptedNode.ReceiverShardId()) +} + +func TestInterceptedTrieNode_Nonce(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.NotEqual(t, 0, interceptedNode.Nonce()) +} + +func TestInterceptedTrieNode_SenderAddress(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.Nil(t, interceptedNode.SenderAddress()) +} + +func TestInterceptedTrieNode_Fee(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.Equal(t, big.NewInt(0), interceptedNode.Fee()) +} + +func TestInterceptedTrieNode_Identifiers(t *testing.T) { + t.Parallel() + + interceptedNode, _ := trie.NewInterceptedTrieNode(getDefaultInterceptedTrieNodeParameters()) + assert.Equal(t, [][]byte{interceptedNode.Hash()}, interceptedNode.Identifiers()) +} From e81a515e1f24e0dee2781456a843a398403e7ca6 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 15:54:20 +0300 Subject: [PATCH 40/79] Fix some tests. --- .../executingSCTransactions_test.go | 8 ++++---- .../executingMiniblocksSc_test.go | 6 +++--- .../smartContract/testdata/first/first.c | 12 ++++++------ .../smartContract/testdata/first/first.wasm | Bin 403 -> 276 bytes .../testdata/first/output/first.wasm | Bin 0 -> 276 bytes .../executingMiniblocksSc_test.go | 6 +++--- .../executingMiniblocksSc/wrc20_arwen_01.wasm | Bin 1517 -> 0 bytes integrationTests/testGameHelperFunctions.go | 6 +++++- 8 files changed, 21 insertions(+), 17 deletions(-) create mode 100755 integrationTests/multiShard/smartContract/testdata/first/output/first.wasm delete mode 100755 integrationTests/singleShard/block/executingMiniblocksSc/wrc20_arwen_01.wasm diff --git a/integrationTests/longTests/executingSCTransactions/executingSCTransactions_test.go b/integrationTests/longTests/executingSCTransactions/executingSCTransactions_test.go index 92409415f1..d969472387 100644 --- a/integrationTests/longTests/executingSCTransactions/executingSCTransactions_test.go +++ b/integrationTests/longTests/executingSCTransactions/executingSCTransactions_test.go @@ -77,7 +77,7 @@ func TestProcessesJoinGameTheSamePlayerMultipleTimesRewardAndEndgameInMultipleRo integrationTests.MintAllNodes(nodes, initialVal) integrationTests.MintAllPlayers(nodes, players, initialVal) - integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine, "") time.Sleep(stepDelay) integrationTests.ProposeBlock(nodes, []int{idxProposer}, round, nonce) integrationTests.SyncBlock(t, nodes, []int{idxProposer}, round) @@ -158,7 +158,7 @@ func TestProcessesJoinGame100PlayersMultipleTimesRewardAndEndgameInMultipleRound integrationTests.MintAllNodes(nodes, initialVal) integrationTests.MintAllPlayers(nodes, players, initialVal) - integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine, "") time.Sleep(stepDelay) integrationTests.ProposeBlock(nodes, []int{idxProposer}, round, nonce) integrationTests.SyncBlock(t, nodes, []int{idxProposer}, round) @@ -249,7 +249,7 @@ func TestProcessesJoinGame100PlayersMultipleTimesRewardAndEndgameInMultipleRound nrRoundsToPropagateMultiShard = 1 } - integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine, "") time.Sleep(stepDelay) for i := 0; i < nrRoundsToPropagateMultiShard; i++ { integrationTests.ProposeBlock(nodes, idxProposers, round, nonce) @@ -345,7 +345,7 @@ func TestProcessesJoinGame100PlayersMultipleTimesRewardAndEndgameInMultipleRound idxProposers[1] = 2 idxProposers[2] = 4 - integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine, "") time.Sleep(stepDelay) for i := 0; i < nrRoundsToPropagateMultiShard; i++ { integrationTests.ProposeBlock(nodes, idxProposers, round, nonce) diff --git a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go index 4c3813d5de..06391a0951 100644 --- a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go +++ b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go @@ -88,7 +88,7 @@ func TestProcessWithScTxsTopUpAndWithdrawOnlyProposers(t *testing.T) { nodes[idxNodeShard1].OwnAccount.Nonce, factory.IELEVirtualMachine, ) - integrationTests.DeployScTx(nodes, idxNodeShard1, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxNodeShard1, string(scCode), factory.IELEVirtualMachine, "") integrationTests.UpdateRound(nodes, round) integrationTests.ProposeBlock(nodes, idxProposers, round, nonce) @@ -236,7 +236,7 @@ func TestProcessWithScTxsJoinAndRewardTwoNodesInShard(t *testing.T) { rewardValue := big.NewInt(10) integrationTests.MintAllNodes(nodes, initialVal) - integrationTests.DeployScTx(nodes, idxProposerShard1, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposerShard1, string(scCode), factory.IELEVirtualMachine, "") round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) @@ -356,7 +356,7 @@ func TestShouldProcessWithScTxsJoinNoCommitShouldProcessedByValidators(t *testin topUpValue := big.NewInt(500) integrationTests.MintAllNodes(nodes, initialVal) - integrationTests.DeployScTx(nodes, idxProposerShard1, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposerShard1, string(scCode), factory.IELEVirtualMachine, "") round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) integrationTests.PlayerJoinsGame( diff --git a/integrationTests/multiShard/smartContract/testdata/first/first.c b/integrationTests/multiShard/smartContract/testdata/first/first.c index 95c7f5edf3..831adda7e7 100644 --- a/integrationTests/multiShard/smartContract/testdata/first/first.c +++ b/integrationTests/multiShard/smartContract/testdata/first/first.c @@ -2,15 +2,15 @@ typedef unsigned char byte; typedef unsigned int i32; typedef unsigned long long i64; -int int64storageStore(byte *key, i64 value); -i64 int64storageLoad(byte *key); +int int64storageStore(byte *key, int keyLength, long long value); +long long int64storageLoad(byte *key, int keyLength); void int64finish(i64 value); byte counterKey[32] = {42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42}; void init() { - int64storageStore(counterKey, 0); + int64storageStore(counterKey, 32, 0); } void callBack() { @@ -18,14 +18,14 @@ void callBack() { void callMe() { - i64 counter = int64storageLoad(counterKey); + i64 counter = int64storageLoad(counterKey, 32); counter++; - int64storageStore(counterKey, counter); + int64storageStore(counterKey, 32, counter); } void numCalled() { - i64 counter = int64storageLoad(counterKey); + i64 counter = int64storageLoad(counterKey, 32); int64finish(counter); } diff --git a/integrationTests/multiShard/smartContract/testdata/first/first.wasm b/integrationTests/multiShard/smartContract/testdata/first/first.wasm index 9a197efadbfc04ded64d3c36da57e04f56951e13..69a78b964e8c1b2f9a2ee92e58122516a354fea0 100755 GIT binary patch delta 165 zcmbQtJcUV=A+b1@k%57MQIsWtxxT)Ru|9#Rexk5{Jqt4su&^=~FfuZ-GBYwTv2ifg zGdeElVBu!hVqwco&CM^WWMbe*PRz-1N=(jXU}gg`eN!1&IP*$#oq_Ds6b4oVtBK?SjA(TkTvdQ%X5fX&*hHnvGh69qxC)l*-60X$c` z{H8WJpvSVuk4059GhjRroFoEVB4WT1Sa`@CCf^$&9sHI^4klq(+Ol4~F_2o%tXb*@ z(^!r}t#i{FZL6HKXlfRV)J*3fLT_&^1bfv>c}?Et5DvdkPyn4fM0dOoyD8IMwYr^~k21J#d@XkI;USLM||11U~@`uN>td5ZLOB;zrC_a7Sn E0NQz66951J diff --git a/integrationTests/multiShard/smartContract/testdata/first/output/first.wasm b/integrationTests/multiShard/smartContract/testdata/first/output/first.wasm new file mode 100755 index 0000000000000000000000000000000000000000..69a78b964e8c1b2f9a2ee92e58122516a354fea0 GIT binary patch literal 276 zcmaKnF>k^!6ol{DPDtw|9bjNWT`FZp9gz}NnD_&+z(7=zAOc88C^k&|41OvOh>D3@ z?%sEAIjAZp0Mr&KH>M_&GGnMtsYVL0gmYc&zp`Tc+po6eMlJNjnFbmjzVcD2W}pVk zJDz7nRxQD};7-D$H4%B7!2Ey=#n+3Ftw{K}&dbe#A(*PwDpAuvaKDLT4e?Rz@}bLm v2Jdsg8RR!&d$AUA@9E*mx;vp`=-i?!JO3|_Dm*t_${%t?AbXM9`$o|XPwqYv literal 0 HcmV?d00001 diff --git a/integrationTests/singleShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go b/integrationTests/singleShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go index aad7c84345..49d90059d8 100644 --- a/integrationTests/singleShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go +++ b/integrationTests/singleShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go @@ -81,7 +81,7 @@ func TestShouldProcessWithScTxsJoinAndRewardOneRound(t *testing.T) { integrationTests.MintAllNodes(nodes, initialVal) integrationTests.MintAllPlayers(nodes, players, initialVal) - integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, string(scCode), factory.IELEVirtualMachine, "") time.Sleep(block.StepDelay) integrationTests.ProposeBlock(nodes, []int{idxProposer}, round, nonce) time.Sleep(block.StepDelay) @@ -171,7 +171,7 @@ func TestShouldProcessMultipleERC20ContractsInSingleShard(t *testing.T) { t.Skip("this is not a short test") } - scCode, err := ioutil.ReadFile("./wrc20_arwen_01.wasm") + scCode, err := ioutil.ReadFile("../../../vm/arwen/testdata/erc20-c-03/wrc20_arwen.wasm") assert.Nil(t, err) maxShards := uint32(1) @@ -224,7 +224,7 @@ func TestShouldProcessMultipleERC20ContractsInSingleShard(t *testing.T) { integrationTests.MintAllNodes(nodes, initialVal) integrationTests.MintAllPlayers(nodes, players, initialVal) - integrationTests.DeployScTx(nodes, idxProposer, hex.EncodeToString(scCode), factory.ArwenVirtualMachine) + integrationTests.DeployScTx(nodes, idxProposer, hex.EncodeToString(scCode), factory.ArwenVirtualMachine, "001000000000") time.Sleep(block.StepDelay) round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, []int{idxProposer}, round, nonce) diff --git a/integrationTests/singleShard/block/executingMiniblocksSc/wrc20_arwen_01.wasm b/integrationTests/singleShard/block/executingMiniblocksSc/wrc20_arwen_01.wasm deleted file mode 100755 index 5790ea43f40d70b2989400a2d8e1571d80e3c309..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1517 zcmds1zi-n(6n^h)CvFZ@k5w0(u#}ah-RK3ufDj9Ufu%X98zT8fWIITeN^_79(v6*^ ze@gz8j7*4;0Rivs+{6o`7f!PMzAxXs@A=+~K^6%D0N!m60H*_h0h>-KpgRnZE@x^m z63M=x??mal-Cm>!;kz*;`lD%Mvn zZ{PP?Nt9&yIfKq=cJf-rGJO+)@0Ynui!-v>@ycxcVhkPcB$1;Oc;|cDeGKe4P_#h6 zliLt{&>-NTrzp!k$B25+KUntFZ)X-l|7ba<`yOHSt3A`PuVeLd*Mfxx>c<^}_AFBC z2L>KgP_6!eA&wRoJv_87R5Tfy5}GxHL+iqhL)4Z^zjcqjx@pR$jPCXbx?5$JQP)BU z*+rveRz;E(hU|UAR;JCOHWxH+3q48uc9863Y)Jl 0 { + data += "@" + initArguments + } + txDeploy := generateTx( nodes[senderIdx].OwnAccount.SkTxSign, nodes[senderIdx].OwnAccount.SingleSigner, From 10e12b2821c3bd57cbf9ab34b585e18b91ff0d16 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 16:39:14 +0300 Subject: [PATCH 41/79] Fix one more test. --- integrationTests/vm/systemVM/stakingSC_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/integrationTests/vm/systemVM/stakingSC_test.go b/integrationTests/vm/systemVM/stakingSC_test.go index 928c455c50..1f4b68af5e 100644 --- a/integrationTests/vm/systemVM/stakingSC_test.go +++ b/integrationTests/vm/systemVM/stakingSC_test.go @@ -13,7 +13,7 @@ import ( "github.com/ElrondNetwork/elrond-go/data/transaction" "github.com/ElrondNetwork/elrond-go/integrationTests" "github.com/ElrondNetwork/elrond-go/vm/factory" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestStakingUnstakingAndUnboundingOnMultiShardEnvironment(t *testing.T) { @@ -138,7 +138,7 @@ func TestStakingUnstakingAndUnboundingOnMultiShardEnvironmentWithValidatorStatis for _, nds := range nodesMap { idx, err := getNodeIndex(nodes, nds[0]) - assert.Nil(t, err) + require.Nil(t, err) idxProposers = append(idxProposers, idx) } @@ -247,14 +247,14 @@ func getNodeIndex(nodeList []*integrationTests.TestProcessorNode, node *integrat } func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9999961980) + expectedValue := big.NewInt(0).SetUint64(9999691980) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) for _, helperNode := range nodes { if helperNode.ShardCoordinator.SelfId() == accShardId { sndAcc := getAccountFromAddrBytes(helperNode.AccntState, node.OwnAccount.Address) - assert.True(t, sndAcc.GetBalance().Cmp(expectedValue) == 0) + require.True(t, sndAcc.GetBalance().Cmp(expectedValue) == 0) break } } @@ -262,14 +262,14 @@ func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { } func checkAccountsAfterStaking(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9499987270) + expectedValue := big.NewInt(0).SetUint64(9499897270) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) for _, helperNode := range nodes { if helperNode.ShardCoordinator.SelfId() == accShardId { sndAcc := getAccountFromAddrBytes(helperNode.AccntState, node.OwnAccount.Address) - assert.True(t, sndAcc.GetBalance().Cmp(expectedValue) == 0) + require.True(t, sndAcc.GetBalance().Cmp(expectedValue) == 0) break } } @@ -283,7 +283,7 @@ func verifyInitialBalance(t *testing.T, nodes []*integrationTests.TestProcessorN for _, helperNode := range nodes { if helperNode.ShardCoordinator.SelfId() == accShardId { sndAcc := getAccountFromAddrBytes(helperNode.AccntState, node.OwnAccount.Address) - assert.Equal(t, initialVal, sndAcc.GetBalance()) + require.Equal(t, initialVal, sndAcc.GetBalance()) break } } From b68c905169d90b9bc5b2f51ce785e7f24a2ce318 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 16:40:45 +0300 Subject: [PATCH 42/79] add missing unit tests for leafNode --- data/trie/leafNode_test.go | 45 ++++++++++++++++++++++++++ data/trie/patriciaMerkleTrie_test.go | 47 ++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/data/trie/leafNode_test.go b/data/trie/leafNode_test.go index bc704c70b7..d7406bfcd2 100644 --- a/data/trie/leafNode_test.go +++ b/data/trie/leafNode_test.go @@ -694,3 +694,48 @@ func TestLeafNode_deleteDifferentKeyShouldNotModifyTrie(t *testing.T) { assert.Equal(t, rootHash, tr.root.getHash()) assert.Equal(t, [][]byte{}, tr.oldHashes) } + +func TestLeafNode_newLeafNodeNilMarshalizerShouldErr(t *testing.T) { + t.Parallel() + + ln, err := newLeafNode([]byte("key"), []byte("val"), nil, mock.HasherMock{}) + assert.Nil(t, ln) + assert.Equal(t, ErrNilMarshalizer, err) +} + +func TestLeafNode_newLeafNodeNilHasherShouldErr(t *testing.T) { + t.Parallel() + + ln, err := newLeafNode([]byte("key"), []byte("val"), &mock.MarshalizerMock{}, nil) + assert.Nil(t, ln) + assert.Equal(t, ErrNilHasher, err) +} + +func TestLeafNode_newLeafNodeOkVals(t *testing.T) { + t.Parallel() + + marsh, hasher := getTestMarshAndHasher() + key := []byte("key") + val := []byte("val") + ln, err := newLeafNode(key, val, marsh, hasher) + + assert.Nil(t, err) + assert.Equal(t, key, ln.Key) + assert.Equal(t, val, ln.Value) + assert.Equal(t, hasher, ln.hasher) + assert.Equal(t, marsh, ln.marsh) + assert.True(t, ln.dirty) +} + +func TestLeafNode_getMarshalizer(t *testing.T) { + t.Parallel() + + marsh, _ := getTestMarshAndHasher() + ln := &leafNode{ + baseNode: &baseNode{ + marsh: marsh, + }, + } + + assert.Equal(t, marsh, ln.getMarshalizer()) +} diff --git a/data/trie/patriciaMerkleTrie_test.go b/data/trie/patriciaMerkleTrie_test.go index e7a428e0a7..d4f462b31d 100644 --- a/data/trie/patriciaMerkleTrie_test.go +++ b/data/trie/patriciaMerkleTrie_test.go @@ -17,6 +17,7 @@ import ( "github.com/ElrondNetwork/elrond-go/hashing" "github.com/ElrondNetwork/elrond-go/hashing/keccak" "github.com/ElrondNetwork/elrond-go/marshal" + "github.com/ElrondNetwork/elrond-go/storage" "github.com/ElrondNetwork/elrond-go/storage/storageUnit" "github.com/stretchr/testify/assert" ) @@ -477,6 +478,52 @@ func TestPatriciaMerkleTrie_GetAllLeaves(t *testing.T) { assert.Equal(t, []byte("cat"), leaves["ddog"]) } +func TestPatriciaMerkleTrie_String(t *testing.T) { + t.Parallel() + + tr := initTrie() + str := tr.String() + assert.NotEqual(t, 0, len(str)) + + tr = emptyTrie() + str = tr.String() + assert.Equal(t, "*** EMPTY TRIE ***\n", str) +} + +func TestPatriciaMerkleTrie_ClosePersister(t *testing.T) { + t.Parallel() + + tempDir, _ := ioutil.TempDir("", strconv.Itoa(rand.Intn(100000))) + arg := storageUnit.ArgDB{ + DBType: storageUnit.LvlDBSerial, + Path: tempDir, + BatchDelaySeconds: 1, + MaxBatchSize: 1, + MaxOpenFiles: 10, + } + db, _ := storageUnit.NewDB(arg) + marshalizer := &mock.ProtobufMarshalizerMock{} + hasher := &mock.KeccakMock{} + + trieStorageManager, _ := trie.NewTrieStorageManager( + db, + marshalizer, + hasher, + config.DBConfig{}, + &mock.EvictionWaitingList{}, + config.TrieStorageManagerConfig{}, + ) + maxTrieLevelInMemory := uint(5) + tr, _ := trie.NewTrie(trieStorageManager, marshalizer, hasher, maxTrieLevelInMemory) + + err := tr.ClosePersister() + assert.Nil(t, err) + + key, err := tr.Database().Get([]byte("key")) + assert.Nil(t, key) + assert.Equal(t, storage.ErrSerialDBIsClosed, err) +} + func BenchmarkPatriciaMerkleTree_Insert(b *testing.B) { tr := emptyTrie() hsh := keccak.Keccak{} From 047a24eb8010a97e8075699372f4fbdd892e88d6 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 16:55:35 +0300 Subject: [PATCH 43/79] Fix tests. --- .../smartContract/scCallingSC_test.go | 10 +++++-- .../smartContract/testdata/counter.wasm | Bin 318 -> 0 bytes .../vm/arwen/testdata/counter/counter.c | 26 ++++++++++++++++++ .../vm/arwen/testdata/counter/counter.export | 4 +++ .../vm/arwen/testdata/counter/counter.wasm | Bin 0 -> 359 bytes .../testdata/counter/output/counter.wasm | Bin 0 -> 359 bytes 6 files changed, 37 insertions(+), 3 deletions(-) delete mode 100755 integrationTests/multiShard/smartContract/testdata/counter.wasm create mode 100644 integrationTests/vm/arwen/testdata/counter/counter.c create mode 100644 integrationTests/vm/arwen/testdata/counter/counter.export create mode 100755 integrationTests/vm/arwen/testdata/counter/counter.wasm create mode 100755 integrationTests/vm/arwen/testdata/counter/output/counter.wasm diff --git a/integrationTests/multiShard/smartContract/scCallingSC_test.go b/integrationTests/multiShard/smartContract/scCallingSC_test.go index 991bf16b20..2bba55210f 100644 --- a/integrationTests/multiShard/smartContract/scCallingSC_test.go +++ b/integrationTests/multiShard/smartContract/scCallingSC_test.go @@ -148,7 +148,7 @@ func TestScDeployAndChangeScOwner(t *testing.T) { firstSCOwner := nodes[0].OwnAccount.Address // deploy the smart contracts - firstSCAddress := putDeploySCToDataPool("./testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) + firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) round := uint64(0) nonce := uint64(0) @@ -249,7 +249,7 @@ func TestScDeployAndClaimSmartContractDeveloperRewards(t *testing.T) { firstSCOwner := nodes[0].OwnAccount.Address // deploy the smart contracts - firstSCAddress := putDeploySCToDataPool("./testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) + firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) round := uint64(0) nonce := uint64(0) @@ -688,7 +688,11 @@ func putDeploySCToDataPool( initArgs string, nodes []*integrationTests.TestProcessorNode, ) []byte { - scCode, _ := ioutil.ReadFile(fileName) + scCode, err := ioutil.ReadFile(fileName) + if err != nil { + panic(fmt.Sprintf("putDeploySCToDataPool(): %s", err)) + } + scCodeString := hex.EncodeToString(scCode) scCodeMetadataString := "0000" diff --git a/integrationTests/multiShard/smartContract/testdata/counter.wasm b/integrationTests/multiShard/smartContract/testdata/counter.wasm deleted file mode 100755 index f676e4d9a54774d7463e5543ebbfa69555ee2896..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318 zcmZ{gL2JT55QX3DZmf1MDSGNjyeK^v?|Sy;A4t&A2D%$bwgsUit0#YkKh;fDP|$an zd3?N?fk9dt0zh4rh`ORWp_;0MDkOlIO3C*3EwgU?S-QMP*E|o6friJoe3qw6P=ob9 zUS&2bzaXTNK`NpR5k-<9TJ3ORay%&gGEyzWCNH)Eoy;x@Hf$YaXUSKu$^TAK)Z-6*BkM};}ePi^KX#F7CyW4h|*Fy@pt@~!X$bYQkB7EqPP84KM ARR910 diff --git a/integrationTests/vm/arwen/testdata/counter/counter.c b/integrationTests/vm/arwen/testdata/counter/counter.c new file mode 100644 index 0000000000..079f1a77cd --- /dev/null +++ b/integrationTests/vm/arwen/testdata/counter/counter.c @@ -0,0 +1,26 @@ +#include "../elrond/context.h" + +byte counterKey[32] = {'m','y','c','o','u','n','t','e','r',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +void init() { + int64storageStore(counterKey, 32, 1); +} + +void increment() { + i64 counter = int64storageLoad(counterKey, 32); + counter++; + int64storageStore(counterKey, 32, counter); + int64finish(counter); +} + +void decrement() { + i64 counter = int64storageLoad(counterKey, 32); + counter--; + int64storageStore(counterKey, 32, counter); + int64finish(counter); +} + +void get() { + i64 counter = int64storageLoad(counterKey, 32); + int64finish(counter); +} diff --git a/integrationTests/vm/arwen/testdata/counter/counter.export b/integrationTests/vm/arwen/testdata/counter/counter.export new file mode 100644 index 0000000000..91723bf1bc --- /dev/null +++ b/integrationTests/vm/arwen/testdata/counter/counter.export @@ -0,0 +1,4 @@ +init +increment +decrement +get diff --git a/integrationTests/vm/arwen/testdata/counter/counter.wasm b/integrationTests/vm/arwen/testdata/counter/counter.wasm new file mode 100755 index 0000000000000000000000000000000000000000..1dfd188f7778425ec5f3195e6f9eb7c0ff798d43 GIT binary patch literal 359 zcmaKoy-veG5QJy%$4R)x2$6!yqM?HZ(c3j0FJLQKf{QyN`#_3>e1Q=4r SgSpAe1Q=4r SgSpA Date: Wed, 13 May 2020 16:56:31 +0300 Subject: [PATCH 44/79] EN-6411: fix after review --- epochStart/bootstrap/syncEpochStartMeta_test.go | 17 +++++++++++------ .../bootstrap/syncValidatorStatus_test.go | 4 +++- update/sync/base_test.go | 2 ++ update/sync/syncHeadersByHash_test.go | 10 +++++----- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/epochStart/bootstrap/syncEpochStartMeta_test.go b/epochStart/bootstrap/syncEpochStartMeta_test.go index bc3e0e731b..d44967ece0 100644 --- a/epochStart/bootstrap/syncEpochStartMeta_test.go +++ b/epochStart/bootstrap/syncEpochStartMeta_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/ElrondNetwork/elrond-go/config" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/epochStart/mock" @@ -22,7 +23,7 @@ func TestNewEpochStartMetaSyncer_ShouldWork(t *testing.T) { require.False(t, check.IfNil(ess)) } -func TestEpochStartMetaSyncer_SyncEpochStartMeta_ErrRegisterMessengerProcessorShouldErr(t *testing.T) { +func TestEpochStartMetaSyncer_SyncEpochStartMetaRegisterMessengerProcessorFailsShouldErr(t *testing.T) { t.Parallel() expectedErr := errors.New("expected error") @@ -36,12 +37,12 @@ func TestEpochStartMetaSyncer_SyncEpochStartMeta_ErrRegisterMessengerProcessorSh args.Messenger = messenger ess, _ := NewEpochStartMetaSyncer(args) - mb, err := ess.SyncEpochStartMeta(1 * time.Second) + mb, err := ess.SyncEpochStartMeta(time.Second) require.Equal(t, expectedErr, err) require.Nil(t, mb) } -func TestEpochStartMetaSyncer_SyncEpochStartMeta_ProcessorReturnsErrorShouldErr(t *testing.T) { +func TestEpochStartMetaSyncer_SyncEpochStartMetaProcessorFailsShouldErr(t *testing.T) { t.Parallel() expectedErr := errors.New("expected error") @@ -62,12 +63,12 @@ func TestEpochStartMetaSyncer_SyncEpochStartMeta_ProcessorReturnsErrorShouldErr( } ess.SetEpochStartMetaBlockInterceptorProcessor(mbIntercProc) - mb, err := ess.SyncEpochStartMeta(1 * time.Second) + mb, err := ess.SyncEpochStartMeta(time.Second) require.Equal(t, expectedErr, err) require.Nil(t, mb) } -func TestEpochStartMetaSyncer_SyncEpochStartMeta_ShouldWork(t *testing.T) { +func TestEpochStartMetaSyncer_SyncEpochStartMetaShouldWork(t *testing.T) { t.Parallel() expectedMb := &block.MetaBlock{Nonce: 37} @@ -88,7 +89,7 @@ func TestEpochStartMetaSyncer_SyncEpochStartMeta_ShouldWork(t *testing.T) { } ess.SetEpochStartMetaBlockInterceptorProcessor(mbIntercProc) - mb, err := ess.SyncEpochStartMeta(1 * time.Second) + mb, err := ess.SyncEpochStartMeta(time.Second) require.NoError(t, err) require.Equal(t, expectedMb, mb) } @@ -110,6 +111,10 @@ func getEpochStartSyncerArgs() ArgsNewEpochStartMetaSyncer { WhitelistHandler: &mock.WhiteListHandlerStub{}, AddressPubkeyConv: mock.NewPubkeyConverterMock(32), NonceConverter: &mock.Uint64ByteSliceConverterMock{}, + StartInEpochConfig: config.EpochStartConfig{ + MinNumConnectedPeersToStart: 2, + MinNumOfPeersToConsiderBlockValid: 2, + }, } } diff --git a/epochStart/bootstrap/syncValidatorStatus_test.go b/epochStart/bootstrap/syncValidatorStatus_test.go index 60a3c97fcf..373ae43841 100644 --- a/epochStart/bootstrap/syncValidatorStatus_test.go +++ b/epochStart/bootstrap/syncValidatorStatus_test.go @@ -80,7 +80,9 @@ func TestSyncValidatorStatus_NodesConfigFromMetaBlock(t *testing.T) { PendingMiniBlockHeaders: nil, }, }, - }} + }, + } + registry, _, err := svs.NodesConfigFromMetaBlock(currMb, prevMb) require.NoError(t, err) require.NotNil(t, registry) diff --git a/update/sync/base_test.go b/update/sync/base_test.go index 0b40063ca9..53bdfd7aac 100644 --- a/update/sync/base_test.go +++ b/update/sync/base_test.go @@ -27,6 +27,7 @@ func TestGetDataFromStorage_NotFoundShouldErr(t *testing.T) { return nil, localErr }, } + res, err := GetDataFromStorage([]byte("test"), storer) require.Equal(t, localErr, err) require.Nil(t, res) @@ -41,6 +42,7 @@ func TestGetDataFromStorage_FoundShouldWork(t *testing.T) { return expRes, nil }, } + res, err := GetDataFromStorage([]byte("test"), storer) require.NoError(t, err) require.Equal(t, expRes, res) diff --git a/update/sync/syncHeadersByHash_test.go b/update/sync/syncHeadersByHash_test.go index a01a95ff96..eb5be74882 100644 --- a/update/sync/syncHeadersByHash_test.go +++ b/update/sync/syncHeadersByHash_test.go @@ -54,7 +54,7 @@ func TestNewMissingheadersByHashSyncer_OkValsShouldWork(t *testing.T) { require.NotNil(t, mhhs) } -func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInCacheShouldWork(t *testing.T) { +func TestSyncHeadersByHash_SyncMissingHeadersByHashHeaderFoundInCacheShouldWork(t *testing.T) { t.Parallel() args := getMisingHeadersByHashSyncerArgs() @@ -69,7 +69,7 @@ func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInCacheShouldWork(t *t require.NoError(t, err) } -func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInStorageShouldWork(t *testing.T) { +func TestSyncHeadersByHash_SyncMissingHeadersByHashHeaderFoundInStorageShouldWork(t *testing.T) { t.Parallel() args := getMisingHeadersByHashSyncerArgs() @@ -91,7 +91,7 @@ func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderInStorageShouldWork(t require.NoError(t, err) } -func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderNotFoundShouldTimeout(t *testing.T) { +func TestSyncHeadersByHash_SyncMissingHeadersByHashHeaderNotFoundShouldTimeout(t *testing.T) { t.Parallel() var errNotFound = errors.New("not found") @@ -115,7 +115,7 @@ func TestSyncHeadersByHash_SyncMissingHeadersByHash_HeaderNotFoundShouldTimeout( require.Equal(t, update.ErrTimeIsOut, err) } -func TestSyncHeadersByHash_GetHeaders_NotSyncedShouldErr(t *testing.T) { +func TestSyncHeadersByHash_GetHeadersNotSyncedShouldErr(t *testing.T) { t.Parallel() args := getMisingHeadersByHashSyncerArgs() @@ -127,7 +127,7 @@ func TestSyncHeadersByHash_GetHeaders_NotSyncedShouldErr(t *testing.T) { require.Equal(t, update.ErrNotSynced, err) } -func TestSyncHeadersByHash_GetHeaders_ShouldReceiveAndReturnOkMb(t *testing.T) { +func TestSyncHeadersByHash_GetHeadersShouldReceiveAndReturnOkMb(t *testing.T) { t.Parallel() var handlerToNotify func(header data.HeaderHandler, shardHeaderHash []byte) From 0a2788b0e719063f78fe9dd2b446ca71f8a572f0 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 17:06:04 +0300 Subject: [PATCH 45/79] Fix tests. --- integrationTests/multiShard/smartContract/scCallingSC_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationTests/multiShard/smartContract/scCallingSC_test.go b/integrationTests/multiShard/smartContract/scCallingSC_test.go index 2bba55210f..0bf9f0b9ac 100644 --- a/integrationTests/multiShard/smartContract/scCallingSC_test.go +++ b/integrationTests/multiShard/smartContract/scCallingSC_test.go @@ -148,7 +148,7 @@ func TestScDeployAndChangeScOwner(t *testing.T) { firstSCOwner := nodes[0].OwnAccount.Address // deploy the smart contracts - firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) + firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) round := uint64(0) nonce := uint64(0) @@ -249,7 +249,7 @@ func TestScDeployAndClaimSmartContractDeveloperRewards(t *testing.T) { firstSCOwner := nodes[0].OwnAccount.Address // deploy the smart contracts - firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) + firstSCAddress := putDeploySCToDataPool("../../vm/arwen/testdata/counter/counter.wasm", firstSCOwner, 0, big.NewInt(50), "", nodes) round := uint64(0) nonce := uint64(0) From 1eac8954bcf6484b95919bff10b3de6045729b17 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 17:12:28 +0300 Subject: [PATCH 46/79] Fix test. --- .../testdata/delegate-mock/delegate.c | 8 ++++---- .../testdata/delegate-mock/delegate.wasm | Bin 738 -> 688 bytes .../testdata/delegate-mock/output/delegate.wasm | Bin 0 -> 688 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100755 integrationTests/multiShard/smartContract/testdata/delegate-mock/output/delegate.wasm diff --git a/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.c b/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.c index df88ee1aa0..20da068dca 100644 --- a/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.c +++ b/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.c @@ -4,8 +4,8 @@ typedef unsigned long long i64; typedef unsigned int bigInt; -int int64storageStore(byte *key, i64 value); -i64 int64storageLoad(byte *key); +int int64storageStore(byte *key, int keyLength, long long value); +long long int64storageLoad(byte *key, int keyLength); i64 int64getArgument(int argumentIndex); int getCallValue(byte *result); void asyncCall(byte *destination, byte *value, byte *data, int length); @@ -20,9 +20,9 @@ byte data[270] = "stake@01@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa void delegate() { i64 stake = int64getArgument(0); - i64 totalStake = int64storageLoad(totalStakeKey); + i64 totalStake = int64storageLoad(totalStakeKey, 32); totalStake += stake; - int64storageStore(totalStakeKey, totalStake); + int64storageStore(totalStakeKey, 32, totalStake); } void sendToStaking() diff --git a/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.wasm b/integrationTests/multiShard/smartContract/testdata/delegate-mock/delegate.wasm index a4ffa6763797a86ed13378ab2262f7abce4e95a7..41107849d26c8615d6356e3880a9a59983b1196c 100755 GIT binary patch delta 150 zcmaFFx`9=aA+b1@k%57MQHd>qv7WImfvFxuGS^QOa&}~7PR%P5%*-n>Gbt{~FG@^L z4F*!F3``(#p7hib=fs?xu*96wR0d{{5NBd>WnMB!kb#AnnTeHk;xs$0P$mrq$A*rE e1_nn3M+SigAb|4)8bQ1ofhG_owb`6;H6s9duPd7X delta 181 zcmdnM`iNDCA+b1@k%57MQJOV@v7WImfoYWnMB!kb#+*nTdsE;#|ArUPh(_M#g&O1|VQ?6v$R$PysU)7#tY{z$|lS x4j`wY11K-h2vTLv%%A{-njlJ(nWF~Che(6P1e!o2mlPEBNap*^WEdtOn-T#4cfu4c&QoIjNv)lu^~9!ub%GRtTrsNjZ9LKD z=rC7C)cLej+5oI@W2#!_>ZFnxpvPNX^$#AqtODZshHG#vi{e}sQw7wcb=l1Hg@+JO zN*D_m-XJ2Q2qcW$FyeC&@U>kUma44k8G$HMh03K-z&0DDv(sv9kMF&^iy!>8%|{?U7A}e(J1<_lR~-^>UHn4gC!gc|ixAf);_qbS_V$NX fX}{pUaJg*Us4Ce%NaR0Pa_Qv0V8Dm{HTC^Bnc~E$ literal 0 HcmV?d00001 From df61173e311627bfee7f48f11b575761c8742b16 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 17:16:49 +0300 Subject: [PATCH 47/79] fix after merge --- data/trie/factory/trieCreator_test.go | 2 +- genesis/process/memoryComponents.go | 3 ++- update/genesis/import.go | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/data/trie/factory/trieCreator_test.go b/data/trie/factory/trieCreator_test.go index 5418c790e3..8894c37b33 100644 --- a/data/trie/factory/trieCreator_test.go +++ b/data/trie/factory/trieCreator_test.go @@ -81,7 +81,7 @@ func TestTrieFactory_CreateNotSupportedCacheType(t *testing.T) { trieStorageCfg := config.StorageConfig{} maxTrieLevelInMemory := uint(5) - _, tr, err := tf.Create(trieStorageCfg, "0", false,maxTrieLevelInMemory) + _, tr, err := tf.Create(trieStorageCfg, "0", false, maxTrieLevelInMemory) require.Nil(t, tr) require.Equal(t, storage.ErrNotSupportedCacheType, err) } diff --git a/genesis/process/memoryComponents.go b/genesis/process/memoryComponents.go index 001c416c6b..915c68415d 100644 --- a/genesis/process/memoryComponents.go +++ b/genesis/process/memoryComponents.go @@ -21,7 +21,8 @@ func createInMemoryAccountAdapter( return nil, err } - tr, err := trie.NewTrie(trieStorage, marshalizer, hasher) + maxTrieLevelInMemory := uint(5) + tr, err := trie.NewTrie(trieStorage, marshalizer, hasher, maxTrieLevelInMemory) if err != nil { return nil, err } diff --git a/update/genesis/import.go b/update/genesis/import.go index 3732eff7b9..1678732c3f 100644 --- a/update/genesis/import.go +++ b/update/genesis/import.go @@ -235,7 +235,8 @@ func (si *stateImport) getTrie(shardID uint32) (data.Trie, error) { return trieForShard, nil } - trieForShard, err := trie.NewTrie(si.trieStorageManager, si.marshalizer, si.hasher) + maxTrieLevelInMemory := uint(2) + trieForShard, err := trie.NewTrie(si.trieStorageManager, si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return nil, err } @@ -251,7 +252,8 @@ func (si *stateImport) importDataTrie(fileName string) error { var err error var address []byte - dataTrie, err := trie.NewTrie(si.trieStorageManager, si.marshalizer, si.hasher) + maxTrieLevelInMemory := uint(5) + dataTrie, err := trie.NewTrie(si.trieStorageManager, si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return err } From 2173d2821eabbcccdf80e58b0c60409aa316c9fc Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Wed, 13 May 2020 18:40:43 +0300 Subject: [PATCH 48/79] save reward value to a special key. --- process/rewardTransaction/export_test.go | 3 ++ process/rewardTransaction/process.go | 26 +++++++++++++ process/rewardTransaction/process_test.go | 47 +++++++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/process/rewardTransaction/export_test.go b/process/rewardTransaction/export_test.go index 8084206194..2bd90b8874 100644 --- a/process/rewardTransaction/export_test.go +++ b/process/rewardTransaction/export_test.go @@ -4,6 +4,9 @@ import ( "github.com/ElrondNetwork/elrond-go/hashing" ) +// RewardKey - +const RewardKey = rewardKey + // Hasher will return the hasher of InterceptedRewardTransaction for using in test files func (inRTx *InterceptedRewardTransaction) Hasher() hashing.Hasher { return inRTx.hasher diff --git a/process/rewardTransaction/process.go b/process/rewardTransaction/process.go index a2f91f790d..5137a6b18a 100644 --- a/process/rewardTransaction/process.go +++ b/process/rewardTransaction/process.go @@ -1,6 +1,9 @@ package rewardTransaction import ( + "math/big" + + "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data/rewardTx" "github.com/ElrondNetwork/elrond-go/data/state" @@ -10,6 +13,8 @@ import ( var _ process.RewardTransactionProcessor = (*rewardTxProcessor)(nil) +const rewardKey = "reward" + type rewardTxProcessor struct { accounts state.AccountsAdapter pubkeyConv state.PubkeyConverter @@ -90,9 +95,30 @@ func (rtp *rewardTxProcessor) ProcessRewardTransaction(rTx *rewardTx.RewardTx) e return err } + rtp.saveAccumulatedRewards(rTx, accHandler) + return rtp.accounts.SaveAccount(accHandler) } +func (rtp *rewardTxProcessor) saveAccumulatedRewards( + rtx *rewardTx.RewardTx, + userAccount state.UserAccountHandler, +) { + if !core.IsSmartContractAddress(rtx.RcvAddr) { + return + } + + existingReward := big.NewInt(0) + fullRewardKey := core.ElrondProtectedKeyPrefix + rewardKey + val, err := userAccount.DataTrieTracker().RetrieveValue([]byte(fullRewardKey)) + if err == nil { + existingReward.SetBytes(val) + } + + existingReward.Add(existingReward, rtx.Value) + userAccount.DataTrieTracker().SaveKeyValue([]byte(fullRewardKey), existingReward.Bytes()) +} + // IsInterfaceNil returns true if there is no value under the interface func (rtp *rewardTxProcessor) IsInterfaceNil() bool { return rtp == nil diff --git a/process/rewardTransaction/process_test.go b/process/rewardTransaction/process_test.go index e3f59d1b41..4710c2744c 100644 --- a/process/rewardTransaction/process_test.go +++ b/process/rewardTransaction/process_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/data/rewardTx" "github.com/ElrondNetwork/elrond-go/data/state" "github.com/ElrondNetwork/elrond-go/process" @@ -208,3 +209,49 @@ func TestRewardTxProcessor_ProcessRewardTransactionShouldWork(t *testing.T) { assert.Nil(t, err) assert.True(t, saveAccountWasCalled) } + +func TestRewardTxProcessor_ProcessRewardTransactionToASmartContractShouldWork(t *testing.T) { + t.Parallel() + + saveAccountWasCalled := false + + address := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6} + userAccount, _ := state.NewUserAccount(address) + accountsDb := &mock.AccountsStub{ + LoadAccountCalled: func(address []byte) (state.AccountHandler, error) { + return userAccount, nil + }, + SaveAccountCalled: func(accountHandler state.AccountHandler) error { + saveAccountWasCalled = true + return nil + }, + } + + rtp, _ := rewardTransaction.NewRewardTxProcessor( + accountsDb, + createMockPubkeyConverter(), + mock.NewMultiShardsCoordinatorMock(3), + ) + + rwdTx := rewardTx.RewardTx{ + Round: 0, + Epoch: 0, + Value: big.NewInt(100), + RcvAddr: address, + } + + err := rtp.ProcessRewardTransaction(&rwdTx) + assert.Nil(t, err) + assert.True(t, saveAccountWasCalled) + val, err := userAccount.DataTrieTracker().RetrieveValue([]byte(core.ElrondProtectedKeyPrefix + rewardTransaction.RewardKey)) + assert.Nil(t, err) + assert.True(t, rwdTx.Value.Cmp(big.NewInt(0).SetBytes(val)) == 0) + + err = rtp.ProcessRewardTransaction(&rwdTx) + assert.Nil(t, err) + assert.True(t, saveAccountWasCalled) + val, err = userAccount.DataTrieTracker().RetrieveValue([]byte(core.ElrondProtectedKeyPrefix + rewardTransaction.RewardKey)) + assert.Nil(t, err) + rwdTx.Value.Add(rwdTx.Value, rwdTx.Value) + assert.True(t, rwdTx.Value.Cmp(big.NewInt(0).SetBytes(val)) == 0) +} From ce537a621ac9486fea957a047fab58fbcf42edec Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 13 May 2020 19:30:32 +0300 Subject: [PATCH 49/79] fix after merge --- integrationTests/testInitializer.go | 2 +- update/genesis/import.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index 36af3ef6d9..208db0a4f9 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -391,7 +391,7 @@ func CreateAccountsDB( trieStorageManager data.StorageManager, ) (*state.AccountsDB, data.Trie) { maxTrieLevelInMemory := uint(5) - tr, _ := trie.NewTrie(trieStorageManager, TestMarshalizer, TestHasher,maxTrieLevelInMemory) + tr, _ := trie.NewTrie(trieStorageManager, TestMarshalizer, TestHasher, maxTrieLevelInMemory) accountFactory := getAccountFactory(accountType) adb, _ := state.NewAccountsDB(tr, sha256.Sha256{}, TestMarshalizer, accountFactory) diff --git a/update/genesis/import.go b/update/genesis/import.go index 4d7f3bebd5..c2daed668a 100644 --- a/update/genesis/import.go +++ b/update/genesis/import.go @@ -239,7 +239,7 @@ func (si *stateImport) getTrie(shardID uint32, accType Type) (data.Trie, error) } maxTrieLevelInMemory := uint(5) - trieForShard, err := trie.NewTrie(trieStorageManager, si.marshalizer, si.hasher,maxTrieLevelInMemory) + trieForShard, err := trie.NewTrie(trieStorageManager, si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return nil, err } @@ -271,7 +271,7 @@ func (si *stateImport) importDataTrie(fileName string) error { } maxTrieLevelInMemory := uint(5) - dataTrie, err := trie.NewTrie(si.trieStorageManagers[triesFactory.UserAccountTrie], si.marshalizer, si.hasher,maxTrieLevelInMemory) + dataTrie, err := trie.NewTrie(si.trieStorageManagers[triesFactory.UserAccountTrie], si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return err } From 6373fd567c22dbd5fc7c9b18cb00ef109feccca4 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 20:22:35 +0300 Subject: [PATCH 50/79] Restore min gas limit. --- integrationTests/testProcessorNode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index e5be7d287b..f71c62c18a 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -114,7 +114,7 @@ var TestBalanceComputationHandler, _ = preprocess.NewBalanceComputation() var MinTxGasPrice = uint64(10) // MinTxGasLimit defines minimum gas limit required by a transaction -var MinTxGasLimit = uint64(10_000) +var MinTxGasLimit = uint64(1_000) // MaxGasLimitPerBlock defines maximum gas limit allowed per one block const MaxGasLimitPerBlock = uint64(3_000_000) From 5d1d9acbaa4a4577b69a31551676bcbd0e2fb181 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 21:10:34 +0300 Subject: [PATCH 51/79] Fix remaining tests. --- integrationTests/testInitializer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index fab47004f1..1599c77abb 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -1154,7 +1154,7 @@ func CreateAndSendTransaction( RcvAddr: rcvAddress, Data: []byte(txData), GasPrice: MinTxGasPrice, - GasLimit: MinTxGasLimit*100 + uint64(len(txData)), + GasLimit: MinTxGasLimit*1000 + uint64(len(txData)), } txBuff, _ := tx.GetDataForSigning(TestAddressPubkeyConverter, TestTxSignMarshalizer) From 39b00195edfe496d9523b0dba7e1e7ed3ae6b991 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 21:41:03 +0300 Subject: [PATCH 52/79] Fix remaining tests. --- integrationTests/vm/systemVM/stakingSC_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integrationTests/vm/systemVM/stakingSC_test.go b/integrationTests/vm/systemVM/stakingSC_test.go index 1f4b68af5e..d7309be033 100644 --- a/integrationTests/vm/systemVM/stakingSC_test.go +++ b/integrationTests/vm/systemVM/stakingSC_test.go @@ -247,7 +247,7 @@ func getNodeIndex(nodeList []*integrationTests.TestProcessorNode, node *integrat } func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9999691980) + expectedValue := big.NewInt(0).SetUint64(9999961980) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) @@ -262,12 +262,13 @@ func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { } func checkAccountsAfterStaking(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9499897270) + expectedValue := big.NewInt(0).SetUint64(9499987270) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) for _, helperNode := range nodes { if helperNode.ShardCoordinator.SelfId() == accShardId { + sndAcc := getAccountFromAddrBytes(helperNode.AccntState, node.OwnAccount.Address) require.True(t, sndAcc.GetBalance().Cmp(expectedValue) == 0) break From 4ad6cadba0106eec7719362370bb6b6b6be83fe0 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 22:14:32 +0300 Subject: [PATCH 53/79] Fix test. --- .../block/executingMiniblocksSc/executingMiniblocksSc_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go index 06391a0951..5c1ea87f53 100644 --- a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go +++ b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go @@ -231,7 +231,7 @@ func TestProcessWithScTxsJoinAndRewardTwoNodesInShard(t *testing.T) { round = integrationTests.IncrementAndPrintRound(round) nonce++ - initialVal := big.NewInt(10000000) + initialVal := big.NewInt(100000000) topUpValue := big.NewInt(500) rewardValue := big.NewInt(10) integrationTests.MintAllNodes(nodes, initialVal) From 4fd8fcb017b2dd0d5807f4881881c8560e0aa7ec Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 22:19:02 +0300 Subject: [PATCH 54/79] Fix test. --- .../block/executingMiniblocksSc/executingMiniblocksSc_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go index 5c1ea87f53..a191b61ef8 100644 --- a/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go +++ b/integrationTests/multiShard/block/executingMiniblocksSc/executingMiniblocksSc_test.go @@ -352,7 +352,7 @@ func TestShouldProcessWithScTxsJoinNoCommitShouldProcessedByValidators(t *testin round = integrationTests.IncrementAndPrintRound(round) nonce++ - initialVal := big.NewInt(10000000) + initialVal := big.NewInt(100000000) topUpValue := big.NewInt(500) integrationTests.MintAllNodes(nodes, initialVal) From 7f5c38af80efaddc345a4cd9e8b5bbff7efeb932 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 22:31:15 +0300 Subject: [PATCH 55/79] Reference latest Arwen (with gas adjustments for deploy). --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c1235e6cea..74ee88cda5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ElrondNetwork/elrond-go go 1.13 require ( - github.com/ElrondNetwork/arwen-wasm-vm v0.3.17 + github.com/ElrondNetwork/arwen-wasm-vm v0.3.18 github.com/ElrondNetwork/concurrent-map v0.1.2 github.com/ElrondNetwork/elrond-go-logger v1.0.3 github.com/ElrondNetwork/elrond-vm v0.0.25 diff --git a/go.sum b/go.sum index c143ca7071..dfea1229a4 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOv github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.17 h1:+kbE3wwOY1BiPRlH0AGQQJ77anpevogCDsTdFNc3OdU= -github.com/ElrondNetwork/arwen-wasm-vm v0.3.17/go.mod h1:cyBSzwbWSGqXJz5excz9PhF4FOhWvS3EFggiFReHsdU= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.18 h1:uXo0P/V+MPYnr6f210Gt9fOTO1NhLcYbqwvlcfUf9Fs= +github.com/ElrondNetwork/arwen-wasm-vm v0.3.18/go.mod h1:cyBSzwbWSGqXJz5excz9PhF4FOhWvS3EFggiFReHsdU= github.com/ElrondNetwork/big-int-util v0.0.5 h1:e/9kK++9ZH/SdIYqLSUPRFYrDZmDWDgff3/7SCydq5I= github.com/ElrondNetwork/big-int-util v0.0.5/go.mod h1:96viBvoTXLjZOhEvE0D+QnAwg1IJLPAK6GVHMbC7Aw4= github.com/ElrondNetwork/concurrent-map v0.1.2 h1:mr2sVF2IPDsJO8DNGzCUiNQOJcadHuIRVZn+QFnCBlE= From 6c633db10ba2838607d89101ce928d48947ec9d9 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 May 2020 22:32:51 +0300 Subject: [PATCH 56/79] Fix after review. --- integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h | 2 +- integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h b/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h index 9a6c2c413b..922faabb0b 100644 --- a/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h +++ b/integrationTests/vm/arwen/testdata/bad-misc/elrond/bigInt.h @@ -25,7 +25,7 @@ void bigIntSetInt64(bigInt destination, long long value); void bigIntFinishUnsigned(bigInt reference); void bigIntFinishSigned(bigInt reference); void bigIntGetCallValue(bigInt destination); -void bigIntgetExternalBalance(byte *address, bigInt result); +void bigIntGetExternalBalance(byte *address, bigInt result); int bigIntByteLength(bigInt reference); int bigIntGetUnsignedBytes(bigInt reference, byte *byte); diff --git a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h index 9a6c2c413b..922faabb0b 100644 --- a/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h +++ b/integrationTests/vm/arwen/testdata/erc20-c-03/elrond/bigInt.h @@ -25,7 +25,7 @@ void bigIntSetInt64(bigInt destination, long long value); void bigIntFinishUnsigned(bigInt reference); void bigIntFinishSigned(bigInt reference); void bigIntGetCallValue(bigInt destination); -void bigIntgetExternalBalance(byte *address, bigInt result); +void bigIntGetExternalBalance(byte *address, bigInt result); int bigIntByteLength(bigInt reference); int bigIntGetUnsignedBytes(bigInt reference, byte *byte); From ff28e381c58564010336fb6cfc00f7ea2219610f Mon Sep 17 00:00:00 2001 From: Sebastian Marian Date: Wed, 13 May 2020 22:47:24 +0300 Subject: [PATCH 57/79] * Added go routines close mechanism through context and io.Close implementation for components: Chronology, Worker, SyncTimer, Bootstrapper --- cmd/node/main.go | 2 +- consensus/chronology/chronology.go | 25 ++++++++++- consensus/interface.go | 2 + consensus/mock/bootstrapMock.go | 11 +++-- consensus/mock/chronologyHandlerMock.go | 5 +++ consensus/mock/sposWorkerMock.go | 5 +++ consensus/mock/syncTimerMock.go | 5 +++ consensus/spos/interface.go | 3 ++ consensus/spos/worker.go | 29 +++++++++++-- epochStart/mock/syncTimerStub.go | 25 ++++++----- facade/mock/syncTimerMock.go | 5 +++ integrationTests/consensus/testInitializer.go | 2 +- integrationTests/mock/syncTimerMock.go | 5 +++ node/mock/syncStub.go | 33 -------------- node/mock/syncTimerStub.go | 38 ++++++++++++++++ node/node.go | 2 +- node/node_test.go | 14 +++--- node/options_test.go | 2 +- ntp/interface.go | 2 + ntp/syncTime.go | 25 ++++++++++- ntp/syncTime_test.go | 2 +- process/interface.go | 5 ++- process/mock/syncTimerMock.go | 5 +++ process/sync/baseSync.go | 43 +++++++++++-------- process/sync/baseSync_test.go | 10 ++++- process/sync/metablock.go | 11 +++-- process/sync/metablock_test.go | 4 +- process/sync/shardblock.go | 10 ++--- process/sync/shardblock_test.go | 4 +- 29 files changed, 231 insertions(+), 103 deletions(-) delete mode 100644 node/mock/syncStub.go create mode 100644 node/mock/syncTimerStub.go diff --git a/cmd/node/main.go b/cmd/node/main.go index f82d1f1802..3fdff554be 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -603,7 +603,7 @@ func startNode(ctx *cli.Context, log logger.Logger, version string) error { log.Debug("config", "file", ctx.GlobalString(nodesFile.Name)) syncer := ntp.NewSyncTime(generalConfig.NTPConfig, nil) - go syncer.StartSync() + syncer.StartSync() log.Debug("NTP average clock offset", "value", syncer.ClockOffset()) diff --git a/consensus/chronology/chronology.go b/consensus/chronology/chronology.go index 90645978c2..d08e32760b 100644 --- a/consensus/chronology/chronology.go +++ b/consensus/chronology/chronology.go @@ -1,6 +1,7 @@ package chronology import ( + "context" "fmt" "sync" "time" @@ -34,6 +35,7 @@ type chronology struct { subroundHandlers []consensus.SubroundHandler mutSubrounds sync.RWMutex appStatusHandler core.AppStatusHandler + cancelFunc func() } // NewChronology creates a new chronology object @@ -114,8 +116,20 @@ func (chr *chronology) RemoveAllSubrounds() { // StartRounds actually starts the chronology and calls the DoWork() method of the subroundHandlers loaded func (chr *chronology) StartRounds() { + var ctx context.Context + ctx, chr.cancelFunc = context.WithCancel(context.Background()) + go chr.startRounds(ctx) +} + +func (chr *chronology) startRounds(ctx context.Context) { for { - time.Sleep(time.Millisecond) + select { + case <-ctx.Done(): + log.Debug("chronology's go routine is stopping...") + return + case <-time.After(time.Millisecond): + } + chr.startRound() } } @@ -199,6 +213,15 @@ func (chr *chronology) loadSubroundHandler(subroundId int) consensus.SubroundHan return chr.subroundHandlers[index] } +// Close will close the endless running go routine +func (chr *chronology) Close() error { + if chr.cancelFunc != nil { + chr.cancelFunc() + } + + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (chr *chronology) IsInterfaceNil() bool { return chr == nil diff --git a/consensus/interface.go b/consensus/interface.go index fca25d47bd..bcf8b47358 100644 --- a/consensus/interface.go +++ b/consensus/interface.go @@ -1,6 +1,7 @@ package consensus import ( + "io" "time" "github.com/ElrondNetwork/elrond-go/data" @@ -45,6 +46,7 @@ type SubroundHandler interface { // ChronologyHandler defines the actions which should be handled by a chronology implementation type ChronologyHandler interface { + io.Closer AddSubround(SubroundHandler) RemoveAllSubrounds() // StartRounds starts rounds in a sequential manner, one after the other diff --git a/consensus/mock/bootstrapMock.go b/consensus/mock/bootstrapMock.go index 29bd9a8d7d..a00b64c9af 100644 --- a/consensus/mock/bootstrapMock.go +++ b/consensus/mock/bootstrapMock.go @@ -12,7 +12,6 @@ type BootstrapperMock struct { AddSyncStateListenerCalled func(func(bool)) GetNodeStateCalled func() core.NodeState StartSyncCalled func() - StopSyncCalled func() SetStatusHandlerCalled func(handler core.AppStatusHandler) error } @@ -46,16 +45,16 @@ func (boot *BootstrapperMock) StartSync() { boot.StartSyncCalled() } -// StopSync - -func (boot *BootstrapperMock) StopSync() { - boot.StopSyncCalled() -} - // SetStatusHandler - func (boot *BootstrapperMock) SetStatusHandler(handler core.AppStatusHandler) error { return boot.SetStatusHandlerCalled(handler) } +// Close - +func (boot *BootstrapperMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (boot *BootstrapperMock) IsInterfaceNil() bool { return boot == nil diff --git a/consensus/mock/chronologyHandlerMock.go b/consensus/mock/chronologyHandlerMock.go index 1933b2b94a..3235ed23ab 100644 --- a/consensus/mock/chronologyHandlerMock.go +++ b/consensus/mock/chronologyHandlerMock.go @@ -41,6 +41,11 @@ func (chrm *ChronologyHandlerMock) StartRounds() { } } +// Close - +func (chrm *ChronologyHandlerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (chrm *ChronologyHandlerMock) IsInterfaceNil() bool { return chrm == nil diff --git a/consensus/mock/sposWorkerMock.go b/consensus/mock/sposWorkerMock.go index c6e8c413d6..0b834eaed1 100644 --- a/consensus/mock/sposWorkerMock.go +++ b/consensus/mock/sposWorkerMock.go @@ -98,6 +98,11 @@ func (sposWorkerMock *SposWorkerMock) SetAppStatusHandler(ash core.AppStatusHand return nil } +// Close - +func (sposWorkerMock *SposWorkerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (sposWorkerMock *SposWorkerMock) IsInterfaceNil() bool { return sposWorkerMock == nil diff --git a/consensus/mock/syncTimerMock.go b/consensus/mock/syncTimerMock.go index baa3038ae2..12b9b8b949 100644 --- a/consensus/mock/syncTimerMock.go +++ b/consensus/mock/syncTimerMock.go @@ -38,6 +38,11 @@ func (stm *SyncTimerMock) CurrentTime() time.Time { return time.Unix(0, 0) } +// Close - +func (stm *SyncTimerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (stm *SyncTimerMock) IsInterfaceNil() bool { return stm == nil diff --git a/consensus/spos/interface.go b/consensus/spos/interface.go index 6c0bf00e74..852851b68a 100644 --- a/consensus/spos/interface.go +++ b/consensus/spos/interface.go @@ -1,6 +1,8 @@ package spos import ( + "io" + "github.com/ElrondNetwork/elrond-go/consensus" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/crypto" @@ -96,6 +98,7 @@ type SubroundsFactory interface { //WorkerHandler represents the interface for the SposWorker type WorkerHandler interface { + io.Closer //AddReceivedMessageCall adds a new handler function for a received message type AddReceivedMessageCall(messageType consensus.MessageType, receivedMessageCall func(cnsDta *consensus.Message) bool) //AddReceivedHeaderHandler adds a new handler function for a received header diff --git a/consensus/spos/worker.go b/consensus/spos/worker.go index a61c34a94d..cdcb1ca838 100644 --- a/consensus/spos/worker.go +++ b/consensus/spos/worker.go @@ -1,6 +1,7 @@ package spos import ( + "context" "encoding/hex" "fmt" "sync" @@ -64,6 +65,7 @@ type Worker struct { signatureSize int publicKeySize int publicKeyBitmapSize int + cancelFunc func() } // WorkerArgs holds the consensus worker arguments @@ -137,7 +139,9 @@ func NewWorker(args *WorkerArgs) (*Worker, error) { maxMessagesInARoundPerPeer := wrk.consensusService.GetMaxMessagesInARoundPerPeer() wrk.antifloodHandler.SetMaxMessagesForTopic(topic, maxMessagesInARoundPerPeer) - go wrk.checkChannels() + var ctx context.Context + ctx, wrk.cancelFunc = context.WithCancel(context.Background()) + go wrk.checkChannels(ctx) wrk.mapDisplayHashConsensusMessage = make(map[string][]*consensus.Message) wrk.publicKeyBitmapSize = wrk.getPublicKeyBitmapSize() @@ -540,9 +544,19 @@ func (wrk *Worker) executeMessage(cnsDtaList []*consensus.Message) { // checkChannels method is used to listen to the channels through which node receives and consumes, // during the round, different messages from the nodes which are in the validators group -func (wrk *Worker) checkChannels() { +func (wrk *Worker) checkChannels(ctx context.Context) { + var rcvDta *consensus.Message + for { - rcvDta := <-wrk.executeMessageChannel + select { + case <-ctx.Done(): + log.Debug("worker's go routine is stopping...") + return + case rcvDta = <-wrk.executeMessageChannel: + case <-time.After(time.Millisecond): + continue + } + msgType := consensus.MessageType(rcvDta.MsgType) if callReceivedMessage, exist := wrk.receivedMessagesCalls[msgType]; exist { if callReceivedMessage(rcvDta) { @@ -625,6 +639,15 @@ func (wrk *Worker) SetAppStatusHandler(ash core.AppStatusHandler) error { return nil } +// Close will close the endless running go routine +func (wrk *Worker) Close() error { + if wrk.cancelFunc != nil { + wrk.cancelFunc() + } + + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (wrk *Worker) IsInterfaceNil() bool { return wrk == nil diff --git a/epochStart/mock/syncTimerStub.go b/epochStart/mock/syncTimerStub.go index 16b59d020c..bb52303a94 100644 --- a/epochStart/mock/syncTimerStub.go +++ b/epochStart/mock/syncTimerStub.go @@ -13,26 +13,31 @@ type SyncTimerStub struct { } // StartSync is a mock implementation for StartSync -func (stm *SyncTimerStub) StartSync() { - stm.StartSyncCalled() +func (sts *SyncTimerStub) StartSync() { + sts.StartSyncCalled() } // ClockOffset is a mock implementation for ClockOffset -func (stm *SyncTimerStub) ClockOffset() time.Duration { - return stm.ClockOffsetCalled() +func (sts *SyncTimerStub) ClockOffset() time.Duration { + return sts.ClockOffsetCalled() } // FormattedCurrentTime is a mock implementation for FormattedCurrentTime -func (stm *SyncTimerStub) FormattedCurrentTime() string { - return stm.FormattedCurrentTimeCalled() +func (sts *SyncTimerStub) FormattedCurrentTime() string { + return sts.FormattedCurrentTimeCalled() } // CurrentTime is a mock implementation for CurrentTime -func (stm *SyncTimerStub) CurrentTime() time.Time { - return stm.CurrentTimeCalled() +func (sts *SyncTimerStub) CurrentTime() time.Time { + return sts.CurrentTimeCalled() +} + +// Close - +func (sts *SyncTimerStub) Close() error { + return nil } // IsInterfaceNil returns true if there is no value under the interface -func (stm *SyncTimerStub) IsInterfaceNil() bool { - return stm == nil +func (sts *SyncTimerStub) IsInterfaceNil() bool { + return sts == nil } diff --git a/facade/mock/syncTimerMock.go b/facade/mock/syncTimerMock.go index d68c83d671..9d3ef9ca6a 100644 --- a/facade/mock/syncTimerMock.go +++ b/facade/mock/syncTimerMock.go @@ -32,6 +32,11 @@ func (stm *SyncTimerMock) CurrentTime() time.Time { return stm.CurrentTimeCalled() } +// Close - +func (stm *SyncTimerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (stm *SyncTimerMock) IsInterfaceNil() bool { return stm == nil diff --git a/integrationTests/consensus/testInitializer.go b/integrationTests/consensus/testInitializer.go index 49ce75918c..9a29f1e562 100644 --- a/integrationTests/consensus/testInitializer.go +++ b/integrationTests/consensus/testInitializer.go @@ -353,7 +353,7 @@ func createConsensusOnlyNode( singleBlsSigner := &mclsinglesig.BlsSingleSigner{} syncer := ntp.NewSyncTime(ntp.NewNTPGoogleConfig(), nil) - go syncer.StartSync() + syncer.StartSync() rounder, _ := round.NewRound( time.Unix(startTime, 0), diff --git a/integrationTests/mock/syncTimerMock.go b/integrationTests/mock/syncTimerMock.go index baa3038ae2..12b9b8b949 100644 --- a/integrationTests/mock/syncTimerMock.go +++ b/integrationTests/mock/syncTimerMock.go @@ -38,6 +38,11 @@ func (stm *SyncTimerMock) CurrentTime() time.Time { return time.Unix(0, 0) } +// Close - +func (stm *SyncTimerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (stm *SyncTimerMock) IsInterfaceNil() bool { return stm == nil diff --git a/node/mock/syncStub.go b/node/mock/syncStub.go deleted file mode 100644 index cf79009bcb..0000000000 --- a/node/mock/syncStub.go +++ /dev/null @@ -1,33 +0,0 @@ -package mock - -import ( - "time" -) - -// SyncStub - -type SyncStub struct { -} - -// StartSync - -func (ss *SyncStub) StartSync() { -} - -// ClockOffset - -func (ss *SyncStub) ClockOffset() time.Duration { - return time.Second -} - -// FormattedCurrentTime - -func (ss *SyncStub) FormattedCurrentTime() string { - return "" -} - -// CurrentTime - -func (ss *SyncStub) CurrentTime() time.Time { - return time.Now() -} - -// IsInterfaceNil returns true if there is no value under the interface -func (ss *SyncStub) IsInterfaceNil() bool { - return ss == nil -} diff --git a/node/mock/syncTimerStub.go b/node/mock/syncTimerStub.go new file mode 100644 index 0000000000..dab1b237e2 --- /dev/null +++ b/node/mock/syncTimerStub.go @@ -0,0 +1,38 @@ +package mock + +import ( + "time" +) + +// SyncTimerStub - +type SyncTimerStub struct { +} + +// StartSync - +func (sts *SyncTimerStub) StartSync() { +} + +// ClockOffset - +func (sts *SyncTimerStub) ClockOffset() time.Duration { + return time.Second +} + +// FormattedCurrentTime - +func (sts *SyncTimerStub) FormattedCurrentTime() string { + return "" +} + +// CurrentTime - +func (sts *SyncTimerStub) CurrentTime() time.Time { + return time.Now() +} + +// Close - +func (sts *SyncTimerStub) Close() error { + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (sts *SyncTimerStub) IsInterfaceNil() bool { + return sts == nil +} diff --git a/node/node.go b/node/node.go index b2c0179edc..4ab9d126e9 100644 --- a/node/node.go +++ b/node/node.go @@ -356,7 +356,7 @@ func (n *Node) StartConsensus() error { return err } - go chronologyHandler.StartRounds() + chronologyHandler.StartRounds() return nil } diff --git a/node/node_test.go b/node/node_test.go index 223eb9b7cd..34a499ce74 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -940,7 +940,7 @@ func TestStartConsensus_ShardBootstrapperNilAccounts(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(mock.NewOneShardCoordinatorMock()), node.WithResolversFinder(rf), node.WithDataStore(store), @@ -1004,7 +1004,7 @@ func TestStartConsensus_ShardBootstrapperNilPoolHolder(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(mock.NewOneShardCoordinatorMock()), node.WithAccountsAdapter(accountDb), node.WithResolversFinder(rf), @@ -1046,7 +1046,7 @@ func TestStartConsensus_MetaBootstrapperNilPoolHolder(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(shardingCoordinator), node.WithDataStore(store), node.WithResolversFinder(&mock.ResolversFinderStub{ @@ -1087,7 +1087,7 @@ func TestStartConsensus_MetaBootstrapperWrongNumberShards(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(shardingCoordinator), node.WithDataStore(&mock.ChainStorerMock{}), node.WithDataPool(&mock.PoolsHolderStub{}), @@ -1140,7 +1140,7 @@ func TestStartConsensus_ShardBootstrapperPubKeyToByteArrayError(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(mock.NewOneShardCoordinatorMock()), node.WithAccountsAdapter(accountDb), node.WithResolversFinder(rf), @@ -1223,7 +1223,7 @@ func TestStartConsensus_ShardBootstrapperInvalidConsensusType(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(mock.NewOneShardCoordinatorMock()), node.WithAccountsAdapter(accountDb), node.WithResolversFinder(rf), @@ -1305,7 +1305,7 @@ func TestStartConsensus_ShardBootstrapper(t *testing.T) { node.WithBlockChain(chainHandler), node.WithRounder(&mock.RounderMock{}), node.WithGenesisTime(time.Now().Local()), - node.WithSyncer(&mock.SyncStub{}), + node.WithSyncer(&mock.SyncTimerStub{}), node.WithShardCoordinator(mock.NewOneShardCoordinatorMock()), node.WithAccountsAdapter(accountDb), node.WithResolversFinder(rf), diff --git a/node/options_test.go b/node/options_test.go index 62bb79a703..f3ea714eb9 100644 --- a/node/options_test.go +++ b/node/options_test.go @@ -426,7 +426,7 @@ func TestWithSyncer_ShouldWork(t *testing.T) { node, _ := NewNode() - sync := &mock.SyncStub{} + sync := &mock.SyncTimerStub{} opt := WithSyncer(sync) err := opt(node) diff --git a/ntp/interface.go b/ntp/interface.go index 9d20f83a6e..5611846ab2 100644 --- a/ntp/interface.go +++ b/ntp/interface.go @@ -1,11 +1,13 @@ package ntp import ( + "io" "time" ) // SyncTimer defines an interface for time synchronization type SyncTimer interface { + io.Closer StartSync() ClockOffset() time.Duration FormattedCurrentTime() string diff --git a/ntp/syncTime.go b/ntp/syncTime.go index 5bf9cc1750..55b94798a3 100644 --- a/ntp/syncTime.go +++ b/ntp/syncTime.go @@ -1,6 +1,7 @@ package ntp import ( + "context" "crypto/rand" "fmt" "math" @@ -95,6 +96,7 @@ type syncTime struct { syncPeriod time.Duration ntpOptions NTPOptions query func(options NTPOptions, hostIndex int) (*ntp.Response, error) + cancelFunc func() } // NewSyncTime creates a syncTime object. The customQueryFunc argument allows the caller to set a different NTP-querying @@ -121,9 +123,21 @@ func NewSyncTime( // StartSync method does the time synchronization at every syncPeriod time elapsed. This method should be started on go // routine func (s *syncTime) StartSync() { + var ctx context.Context + ctx, s.cancelFunc = context.WithCancel(context.Background()) + go s.startSync(ctx) +} + +func (s *syncTime) startSync(ctx context.Context) { for { s.sync() - time.Sleep(s.getSleepTime()) + + select { + case <-ctx.Done(): + log.Debug("syncTime's go routine is stopping...") + return + case <-time.After(s.getSleepTime()): + } } } @@ -258,6 +272,15 @@ func (s *syncTime) CurrentTime() time.Time { return currentTime } +// Close will close the endless running go routine +func (s *syncTime) Close() error { + if s.cancelFunc != nil { + s.cancelFunc() + } + + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (s *syncTime) IsInterfaceNil() bool { return s == nil diff --git a/ntp/syncTime_test.go b/ntp/syncTime_test.go index 8116dc634f..0e103b7664 100644 --- a/ntp/syncTime_test.go +++ b/ntp/syncTime_test.go @@ -130,7 +130,7 @@ func TestGetOffset(t *testing.T) { func TestCallQuery(t *testing.T) { st := ntp2.NewSyncTime(config.NTPConfig{Hosts: []string{""}, SyncPeriodSeconds: 1}, queryMock4) - go st.StartSync() + st.StartSync() assert.NotNil(t, st.Query()) assert.Equal(t, time.Second, st.SyncPeriod()) diff --git a/process/interface.go b/process/interface.go index f91dcc69d6..2f989d8b52 100644 --- a/process/interface.go +++ b/process/interface.go @@ -1,6 +1,7 @@ package process import ( + "io" "math/big" "time" @@ -16,7 +17,7 @@ import ( "github.com/ElrondNetwork/elrond-go/process/block/processedMb" "github.com/ElrondNetwork/elrond-go/sharding" "github.com/ElrondNetwork/elrond-go/storage" - vmcommon "github.com/ElrondNetwork/elrond-vm-common" + "github.com/ElrondNetwork/elrond-vm-common" ) // TransactionProcessor is the main interface for transaction execution engine @@ -290,9 +291,9 @@ type HashAccesser interface { // Bootstrapper is an interface that defines the behaviour of a struct that is able // to synchronize the node type Bootstrapper interface { + io.Closer AddSyncStateListener(func(isSyncing bool)) GetNodeState() core.NodeState - StopSync() StartSync() SetStatusHandler(handler core.AppStatusHandler) error IsInterfaceNil() bool diff --git a/process/mock/syncTimerMock.go b/process/mock/syncTimerMock.go index 54e01b0e14..cb35ff7882 100644 --- a/process/mock/syncTimerMock.go +++ b/process/mock/syncTimerMock.go @@ -38,6 +38,11 @@ func (stm SyncTimerMock) CurrentTime() time.Time { return time.Unix(0, 0) } +// Close - +func (stm *SyncTimerMock) Close() error { + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (stm *SyncTimerMock) IsInterfaceNil() bool { return stm == nil diff --git a/process/sync/baseSync.go b/process/sync/baseSync.go index e0ea613421..4400b076fb 100644 --- a/process/sync/baseSync.go +++ b/process/sync/baseSync.go @@ -2,6 +2,7 @@ package sync import ( "bytes" + "context" "math" "sync" "time" @@ -105,6 +106,7 @@ type baseBootstrap struct { miniBlocksProvider process.MiniBlockProvider poolsHolder dataRetriever.PoolsHolder mutRequestHeaders sync.Mutex + cancelFunc func() } // setRequestedHeaderNonce method sets the header nonce requested by the sync mechanism @@ -455,28 +457,23 @@ func (boot *baseBootstrap) requestHeadersFromNonceIfMissing(fromNonce uint64) { boot.requestHeaders(fromNonce, toNonce) } -// StopSync method will stop SyncBlocks -func (boot *baseBootstrap) StopSync() { - boot.chStopSync <- true -} - // syncBlocks method calls repeatedly synchronization method SyncBlock -func (boot *baseBootstrap) syncBlocks() { +func (boot *baseBootstrap) syncBlocks(ctx context.Context) { for { - time.Sleep(sleepTime) + select { + case <-ctx.Done(): + log.Debug("bootstrap's go routine is stopping...") + return + case <-time.After(sleepTime): + } if !boot.networkWatcher.IsConnectedToTheNetwork() { continue } - select { - case <-boot.chStopSync: - return - default: - err := boot.syncStarter.SyncBlock() - if err != nil { - log.Debug("SyncBlock", "error", err.Error()) - } + err := boot.syncStarter.SyncBlock() + if err != nil { + log.Debug("SyncBlock", "error", err.Error()) } } } @@ -956,8 +953,6 @@ func (boot *baseBootstrap) init() { boot.poolsHolder.MiniBlocks().RegisterHandler(boot.receivedMiniblock) boot.headers.RegisterHandler(boot.processReceivedHeader) - boot.chStopSync = make(chan bool) - boot.statusHandler = statusHandler.NewNilStatusHandler() boot.syncStateListeners = make([]func(bool), 0) @@ -1000,3 +995,17 @@ func (boot *baseBootstrap) GetNodeState() core.NodeState { return core.NsNotSynchronized } + +// Close will close the endless running go routine +func (boot *baseBootstrap) Close() error { + if boot.cancelFunc != nil { + boot.cancelFunc() + } + + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (boot *baseBootstrap) IsInterfaceNil() bool { + return boot == nil +} diff --git a/process/sync/baseSync_test.go b/process/sync/baseSync_test.go index e111976222..e0562c79f9 100644 --- a/process/sync/baseSync_test.go +++ b/process/sync/baseSync_test.go @@ -1,6 +1,7 @@ package sync import ( + "context" "sync/atomic" "testing" "time" @@ -31,9 +32,12 @@ func TestBaseBootstrap_SyncBlocksShouldNotCallSyncIfNotConnectedToTheNetwork(t * }, } - go boot.syncBlocks() + ctx, cancelFunc := context.WithCancel(context.Background()) + go boot.syncBlocks(ctx) + //make sure go routine started and waited a few cycles of boot.syncBlocks time.Sleep(time.Second + sleepTime*10) + cancelFunc() assert.Equal(t, uint32(0), atomic.LoadUint32(&numCalls)) } @@ -57,10 +61,12 @@ func TestBaseBootstrap_SyncBlocksShouldCallSyncIfConnectedToTheNetwork(t *testin }, } - go boot.syncBlocks() + ctx, cancelFunc := context.WithCancel(context.Background()) + go boot.syncBlocks(ctx) //make sure go routine started and waited a few cycles of boot.syncBlocks time.Sleep(time.Second + sleepTime*10) + cancelFunc() assert.True(t, atomic.LoadUint32(&numCalls) > 0) } diff --git a/process/sync/metablock.go b/process/sync/metablock.go index 88a7c88375..3f4188d6dd 100644 --- a/process/sync/metablock.go +++ b/process/sync/metablock.go @@ -1,6 +1,8 @@ package sync import ( + "context" + "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data" @@ -115,7 +117,9 @@ func (boot *MetaBootstrap) StartSync() { boot.setLastEpochStartRound() } - go boot.syncBlocks() + var ctx context.Context + ctx, boot.cancelFunc = context.WithCancel(context.Background()) + go boot.syncBlocks(ctx) } func (boot *MetaBootstrap) setLastEpochStartRound() { @@ -249,11 +253,6 @@ func (boot *MetaBootstrap) getCurrHeader() (data.HeaderHandler, error) { return header, nil } -// IsInterfaceNil returns true if there is no value under the interface -func (boot *MetaBootstrap) IsInterfaceNil() bool { - return boot == nil -} - func (boot *MetaBootstrap) haveHeaderInPoolWithNonce(nonce uint64) bool { _, _, err := process.GetMetaHeaderFromPoolWithNonce( nonce, diff --git a/process/sync/metablock_test.go b/process/sync/metablock_test.go index d25aba7641..7f02c09ecc 100644 --- a/process/sync/metablock_test.go +++ b/process/sync/metablock_test.go @@ -373,7 +373,7 @@ func TestMetaBootstrap_ShouldNotNeedToSync(t *testing.T) { bs.StartSync() time.Sleep(200 * time.Millisecond) - bs.StopSync() + bs.Close() } func TestMetaBootstrap_SyncShouldSyncOneBlock(t *testing.T) { @@ -452,7 +452,7 @@ func TestMetaBootstrap_SyncShouldSyncOneBlock(t *testing.T) { time.Sleep(500 * time.Millisecond) - bs.StopSync() + bs.Close() } func TestMetaBootstrap_ShouldReturnNilErr(t *testing.T) { diff --git a/process/sync/shardblock.go b/process/sync/shardblock.go index b49d11490a..3e29a33038 100644 --- a/process/sync/shardblock.go +++ b/process/sync/shardblock.go @@ -1,6 +1,7 @@ package sync import ( + "context" "math" "github.com/ElrondNetwork/elrond-go/core" @@ -112,7 +113,9 @@ func (boot *ShardBootstrap) StartSync() { boot.blockProcessor.SetNumProcessedObj(numTxs) } - go boot.syncBlocks() + var ctx context.Context + ctx, boot.cancelFunc = context.WithCancel(context.Background()) + go boot.syncBlocks(ctx) } // SyncBlock method actually does the synchronization. It requests the next block header from the pool @@ -227,11 +230,6 @@ func (boot *ShardBootstrap) getCurrHeader() (data.HeaderHandler, error) { return header, nil } -// IsInterfaceNil returns true if there is no value under the interface -func (boot *ShardBootstrap) IsInterfaceNil() bool { - return boot == nil -} - func (boot *ShardBootstrap) haveHeaderInPoolWithNonce(nonce uint64) bool { _, _, err := process.GetShardHeaderFromPoolWithNonce( nonce, diff --git a/process/sync/shardblock_test.go b/process/sync/shardblock_test.go index 26d240dcc8..b6694895d7 100644 --- a/process/sync/shardblock_test.go +++ b/process/sync/shardblock_test.go @@ -587,7 +587,7 @@ func TestBootstrap_ShouldNotNeedToSync(t *testing.T) { bs.StartSync() time.Sleep(200 * time.Millisecond) - bs.StopSync() + bs.Close() } func TestBootstrap_SyncShouldSyncOneBlock(t *testing.T) { @@ -685,7 +685,7 @@ func TestBootstrap_SyncShouldSyncOneBlock(t *testing.T) { time.Sleep(500 * time.Millisecond) - bs.StopSync() + bs.Close() } func TestBootstrap_ShouldReturnNilErr(t *testing.T) { From 4d044bb0f49fba7b5f1177ce31ea857a8b765657 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 14 May 2020 13:25:18 +0300 Subject: [PATCH 58/79] Fix after review. --- dataRetriever/constants.go | 3 -- dataRetriever/txpool/argShardedTxPool.go | 28 ++++++------ dataRetriever/txpool/shardedTxPool_test.go | 4 +- storage/txcache/config.go | 5 -- storage/txcache/disabledCache.go | 53 ++++++++-------------- storage/txcache/txCache_test.go | 24 +++++----- 6 files changed, 47 insertions(+), 70 deletions(-) diff --git a/dataRetriever/constants.go b/dataRetriever/constants.go index e171d666b7..98ebbc2b51 100644 --- a/dataRetriever/constants.go +++ b/dataRetriever/constants.go @@ -2,6 +2,3 @@ package dataRetriever // TxPoolNumSendersToEvictInOneStep instructs tx pool eviction algorithm to remove this many senders when eviction takes place const TxPoolNumSendersToEvictInOneStep = uint32(100) - -// TxPoolMinSizeInBytes is the lower limit of the tx cache / eviction parameter "sizeInBytes" -const TxPoolMinSizeInBytes = uint32(40960) diff --git a/dataRetriever/txpool/argShardedTxPool.go b/dataRetriever/txpool/argShardedTxPool.go index 204a5c754c..a99600ab92 100644 --- a/dataRetriever/txpool/argShardedTxPool.go +++ b/dataRetriever/txpool/argShardedTxPool.go @@ -18,26 +18,26 @@ type ArgShardedTxPool struct { func (args *ArgShardedTxPool) verify() error { config := args.Config - if config.SizeInBytes < dataRetriever.TxPoolMinSizeInBytes { - return fmt.Errorf("%w: config.SizeInBytes is less than [dataRetriever.TxPoolMinSizeInBytes]", dataRetriever.ErrCacheConfigInvalidSizeInBytes) + if config.SizeInBytes == 0 { + return fmt.Errorf("%w: config.SizeInBytes is not valid", dataRetriever.ErrCacheConfigInvalidSizeInBytes) } - if config.SizeInBytesPerSender < dataRetriever.TxPoolMinSizeInBytes { - return fmt.Errorf("%w: config.SizeInBytesPerSender is less than [dataRetriever.TxPoolMinSizeInBytes]", dataRetriever.ErrCacheConfigInvalidSizeInBytes) + if config.SizeInBytesPerSender == 0 { + return fmt.Errorf("%w: config.SizeInBytesPerSender is not valid", dataRetriever.ErrCacheConfigInvalidSizeInBytes) } - if config.Size < 1 { - return fmt.Errorf("%w: config.Size is less than 1", dataRetriever.ErrCacheConfigInvalidSize) + if config.Size == 0 { + return fmt.Errorf("%w: config.Size is not valid", dataRetriever.ErrCacheConfigInvalidSize) } - if config.SizePerSender < 1 { - return fmt.Errorf("%w: config.SizePerSender is less than 1", dataRetriever.ErrCacheConfigInvalidSize) + if config.SizePerSender == 0 { + return fmt.Errorf("%w: config.SizePerSender is not valid", dataRetriever.ErrCacheConfigInvalidSize) } - if config.Shards < 1 { - return fmt.Errorf("%w: config.Shards (map chunks) is less than 1", dataRetriever.ErrCacheConfigInvalidShards) + if config.Shards == 0 { + return fmt.Errorf("%w: config.Shards (map chunks) is not valid", dataRetriever.ErrCacheConfigInvalidShards) } - if args.MinGasPrice < 1 { - return fmt.Errorf("%w: MinGasPrice is less than 1", dataRetriever.ErrCacheConfigInvalidEconomics) + if args.MinGasPrice == 0 { + return fmt.Errorf("%w: MinGasPrice is not valid", dataRetriever.ErrCacheConfigInvalidEconomics) } - if args.NumberOfShards < 1 { - return fmt.Errorf("%w: NumberOfShards is less than 1", dataRetriever.ErrCacheConfigInvalidSharding) + if args.NumberOfShards == 0 { + return fmt.Errorf("%w: NumberOfShards is not valid", dataRetriever.ErrCacheConfigInvalidSharding) } return nil diff --git a/dataRetriever/txpool/shardedTxPool_test.go b/dataRetriever/txpool/shardedTxPool_test.go index a0b3a8b920..94aa8fa53d 100644 --- a/dataRetriever/txpool/shardedTxPool_test.go +++ b/dataRetriever/txpool/shardedTxPool_test.go @@ -27,14 +27,14 @@ func Test_NewShardedTxPool_WhenBadConfig(t *testing.T) { goodArgs := ArgShardedTxPool{Config: storageUnit.CacheConfig{Size: 100, SizePerSender: 10, SizeInBytes: 409600, SizeInBytesPerSender: 40960, Shards: 16}, MinGasPrice: 200000000000, NumberOfShards: 1} args := goodArgs - args.Config.SizeInBytes = 1 + args.Config.SizeInBytes = 0 pool, err := NewShardedTxPool(args) require.Nil(t, pool) require.NotNil(t, err) require.Errorf(t, err, dataRetriever.ErrCacheConfigInvalidSizeInBytes.Error()) args = goodArgs - args.Config.SizeInBytesPerSender = 1 + args.Config.SizeInBytesPerSender = 0 pool, err = NewShardedTxPool(args) require.Nil(t, pool) require.NotNil(t, err) diff --git a/storage/txcache/config.go b/storage/txcache/config.go index 62ee3a08b0..1be512220a 100644 --- a/storage/txcache/config.go +++ b/storage/txcache/config.go @@ -19,23 +19,18 @@ func (config *CacheConfig) verify() error { if len(config.Name) == 0 { return fmt.Errorf("%w: config.Name is invalid", errInvalidCacheConfig) } - if config.NumChunksHint == 0 { return fmt.Errorf("%w: config.NumChunksHint is invalid", errInvalidCacheConfig) } - if config.NumBytesPerSenderThreshold == 0 { return fmt.Errorf("%w: config.NumBytesPerSenderThreshold is invalid", errInvalidCacheConfig) } - if config.CountPerSenderThreshold == 0 { return fmt.Errorf("%w: config.CountPerSenderThreshold is invalid", errInvalidCacheConfig) } - if config.MinGasPriceNanoErd == 0 { return fmt.Errorf("%w: config.MinGasPriceNanoErd is invalid", errInvalidCacheConfig) } - if config.EvictionEnabled { if config.NumBytesThreshold == 0 { return fmt.Errorf("%w: config.NumBytesThreshold is invalid", errInvalidCacheConfig) diff --git a/storage/txcache/disabledCache.go b/storage/txcache/disabledCache.go index 663f3392da..cf587439a5 100644 --- a/storage/txcache/disabledCache.go +++ b/storage/txcache/disabledCache.go @@ -15,106 +15,89 @@ func NewDisabledCache() *DisabledCache { return &DisabledCache{} } -// AddTx - +// AddTx does nothing func (cache *DisabledCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { - log.Error("DisabledCache.AddTx()") return false, false } -// GetByTxHash - +// GetByTxHash returns no transaction func (cache *DisabledCache) GetByTxHash(txHash []byte) (*WrappedTransaction, bool) { - log.Error("DisabledCache.GetByTxHash()") return nil, false } -// SelectTransactions - +// SelectTransactions returns an empty slice func (cache *DisabledCache) SelectTransactions(numRequested int, batchSizePerSender int) []*WrappedTransaction { - log.Error("DisabledCache.SelectTransactions()") return make([]*WrappedTransaction, 0) } -// RemoveTxByHash - +// RemoveTxByHash does nothing func (cache *DisabledCache) RemoveTxByHash(txHash []byte) error { - log.Error("DisabledCache.RemoveTxByHash()") return nil } -// CountTx - +// CountTx returns zero func (cache *DisabledCache) CountTx() int64 { - log.Error("DisabledCache.CountTx()") return 0 } -// Len - +// Len returns zero func (cache *DisabledCache) Len() int { - log.Error("DisabledCache.Len()") return 0 } -// ForEachTransaction - +// ForEachTransaction does nothing func (cache *DisabledCache) ForEachTransaction(function ForEachTransaction) { - log.Error("DisabledCache.ForEachTransaction()") } -// Clear - +// Clear does nothing func (cache *DisabledCache) Clear() { - log.Error("DisabledCache.Clear()") } -// Put - +// Put does nothing func (cache *DisabledCache) Put(key []byte, value interface{}) (evicted bool) { - log.Error("DisabledCache.Put()") return false } -// Get - +// Get returns no transaction func (cache *DisabledCache) Get(key []byte) (value interface{}, ok bool) { return nil, false } -// Has - +// Has returns false func (cache *DisabledCache) Has(key []byte) bool { - log.Error("DisabledCache.Has is not implemented") return false } -// Peek - +// Peek returns no transaction func (cache *DisabledCache) Peek(key []byte) (value interface{}, ok bool) { - log.Error("DisabledCache.DisabledCache()") return nil, false } -// HasOrAdd - +// HasOrAdd returns false, does nothing func (cache *DisabledCache) HasOrAdd(key []byte, value interface{}) (ok, evicted bool) { - log.Error("DisabledCache.HasOrAdd()") return false, false } -// Remove - +// Remove does nothing func (cache *DisabledCache) Remove(key []byte) { - log.Error("DisabledCache.Remove()") } -// RemoveOldest - +// RemoveOldest does nothing func (cache *DisabledCache) RemoveOldest() { - log.Error("DisabledCache.RemoveOldest()") } -// Keys - +// Keys returns an empty slice func (cache *DisabledCache) Keys() txHashes { - log.Error("DisabledCache.Keys()") return make([][]byte, 0) } -// MaxSize - +// MaxSize returns zero func (cache *DisabledCache) MaxSize() int { - log.Error("DisabledCache.MaxSize()") return 0 } -// RegisterHandler - +// RegisterHandler does nothing func (cache *DisabledCache) RegisterHandler(func(key []byte, value interface{})) { - log.Error("DisabledCache.RegisterHandler()") } // IsInterfaceNil returns true if there is no value under the interface diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index b04a9cec2b..507db7e375 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -1,6 +1,7 @@ package txcache import ( + "errors" "fmt" "math" "sync" @@ -40,41 +41,42 @@ func Test_NewTxCache(t *testing.T) { badConfig := config badConfig.Name = "" - requireErrorOnNewTxCache(t, badConfig, "config.Name") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.Name") badConfig = config badConfig.NumChunksHint = 0 - requireErrorOnNewTxCache(t, badConfig, "config.NumChunksHint") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.NumChunksHint") badConfig = config badConfig.NumBytesPerSenderThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, "config.NumBytesPerSenderThreshold") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.NumBytesPerSenderThreshold") badConfig = config badConfig.CountPerSenderThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, "config.CountPerSenderThreshold") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.CountPerSenderThreshold") badConfig = config badConfig.MinGasPriceNanoErd = 0 - requireErrorOnNewTxCache(t, badConfig, "config.MinGasPriceNanoErd") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.MinGasPriceNanoErd") badConfig = withEvictionConfig badConfig.NumBytesThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, "config.NumBytesThreshold") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.NumBytesThreshold") badConfig = withEvictionConfig badConfig.CountThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, "config.CountThreshold") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.CountThreshold") badConfig = withEvictionConfig badConfig.NumSendersToEvictInOneStep = 0 - requireErrorOnNewTxCache(t, badConfig, "config.NumSendersToEvictInOneStep") + requireErrorOnNewTxCache(t, badConfig, errInvalidCacheConfig, "config.NumSendersToEvictInOneStep") } -func requireErrorOnNewTxCache(t *testing.T, config CacheConfig, errMessage string) { - cache, err := NewTxCache(config) - require.Contains(t, err.Error(), errMessage) +func requireErrorOnNewTxCache(t *testing.T, config CacheConfig, errExpected error, errPartialMessage string) { + cache, errReceived := NewTxCache(config) require.Nil(t, cache) + require.True(t, errors.Is(errReceived, errExpected)) + require.Contains(t, errReceived.Error(), errPartialMessage) } func Test_AddTx(t *testing.T) { From a9c5788157411eb39050724b1174e0e402a41073 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Thu, 14 May 2020 13:26:47 +0300 Subject: [PATCH 59/79] fix after review --- data/trie/extensionNode_test.go | 1 - genesis/process/memoryComponents.go | 3 ++- integrationTests/testInitializer.go | 3 +-- integrationTests/vm/testInitializer.go | 3 ++- update/genesis/import.go | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data/trie/extensionNode_test.go b/data/trie/extensionNode_test.go index 86fda1ebcf..7d83dddc92 100644 --- a/data/trie/extensionNode_test.go +++ b/data/trie/extensionNode_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/ElrondNetwork/elrond-go/data" - "github.com/ElrondNetwork/elrond-go/data/mock" "github.com/ElrondNetwork/elrond-go/storage/lrucache" "github.com/stretchr/testify/assert" diff --git a/genesis/process/memoryComponents.go b/genesis/process/memoryComponents.go index 887e61d212..c879c8de22 100644 --- a/genesis/process/memoryComponents.go +++ b/genesis/process/memoryComponents.go @@ -8,13 +8,14 @@ import ( "github.com/ElrondNetwork/elrond-go/marshal" ) +const maxTrieLevelInMemory = uint(5) + func createAccountAdapter( marshalizer marshal.Marshalizer, hasher hashing.Hasher, accountFactory state.AccountFactory, trieStorage data.StorageManager, ) (state.AccountsAdapter, error) { - maxTrieLevelInMemory := uint(5) tr, err := trie.NewTrie(trieStorage, marshalizer, hasher, maxTrieLevelInMemory) if err != nil { return nil, err diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index 208db0a4f9..eed9d3eb51 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -75,6 +75,7 @@ const ( shuffleBetweenShards = false adaptivity = false hysteresis = float32(0.2) + maxTrieLevelInMemory = uint(5) ) // Type defines account types to save in accounts trie @@ -390,7 +391,6 @@ func CreateAccountsDB( accountType Type, trieStorageManager data.StorageManager, ) (*state.AccountsDB, data.Trie) { - maxTrieLevelInMemory := uint(5) tr, _ := trie.NewTrie(trieStorageManager, TestMarshalizer, TestHasher, maxTrieLevelInMemory) accountFactory := getAccountFactory(accountType) @@ -780,7 +780,6 @@ func CreateNewDefaultTrie() data.Trie { } trieStorage, _ := trie.NewTrieStorageManager(CreateMemUnit(), TestMarshalizer, TestHasher, config.DBConfig{}, ewl, generalCfg) - maxTrieLevelInMemory := uint(5) tr, _ := trie.NewTrie(trieStorage, TestMarshalizer, TestHasher, maxTrieLevelInMemory) return tr } diff --git a/integrationTests/vm/testInitializer.go b/integrationTests/vm/testInitializer.go index aa62413da3..4b4ec80a90 100644 --- a/integrationTests/vm/testInitializer.go +++ b/integrationTests/vm/testInitializer.go @@ -46,6 +46,8 @@ var pubkeyConv, _ = pubkeyConverter.NewHexPubkeyConverter(32) var log = logger.GetOrCreate("integrationtests") +const maxTrieLevelInMemory = uint(5) + // VMTestContext - type VMTestContext struct { TxProcessor process.TransactionProcessor @@ -118,7 +120,6 @@ func CreateInMemoryShardAccountsDB() *state.AccountsDB { generalCfg, ) - maxTrieLevelInMemory := uint(5) tr, _ := trie.NewTrie(trieStorage, marsh, testHasher, maxTrieLevelInMemory) adb, _ := state.NewAccountsDB(tr, testHasher, marsh, &accountFactory{}) diff --git a/update/genesis/import.go b/update/genesis/import.go index c2daed668a..17a6f0498a 100644 --- a/update/genesis/import.go +++ b/update/genesis/import.go @@ -22,6 +22,8 @@ import ( var _ update.ImportHandler = (*stateImport)(nil) +const maxTrieLevelInMemory = uint(5) + // ArgsNewStateImport is the arguments structure to create a new state importer type ArgsNewStateImport struct { Reader update.MultiFileReader @@ -238,7 +240,6 @@ func (si *stateImport) getTrie(shardID uint32, accType Type) (data.Trie, error) trieStorageManager = si.trieStorageManagers[triesFactory.PeerAccountTrie] } - maxTrieLevelInMemory := uint(5) trieForShard, err := trie.NewTrie(trieStorageManager, si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return nil, err @@ -270,7 +271,6 @@ func (si *stateImport) importDataTrie(fileName string) error { return fmt.Errorf("%w wanted a roothash", update.ErrWrongTypeAssertion) } - maxTrieLevelInMemory := uint(5) dataTrie, err := trie.NewTrie(si.trieStorageManagers[triesFactory.UserAccountTrie], si.marshalizer, si.hasher, maxTrieLevelInMemory) if err != nil { return err From b488b4d9a033af21075f553f4411b974ecde6e6b Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 14 May 2020 14:35:47 +0300 Subject: [PATCH 60/79] Fix after review, plus fix tests to use the correct Equals() function. --- storage/txcache/maps/bucketSortedMap_test.go | 8 +-- storage/txcache/txCache_test.go | 16 +++--- storage/txcache/txListForSender.go | 13 ++--- storage/txcache/txListForSender_test.go | 51 +++++++++++++------- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/storage/txcache/maps/bucketSortedMap_test.go b/storage/txcache/maps/bucketSortedMap_test.go index 98cf23948c..94c075a0c8 100644 --- a/storage/txcache/maps/bucketSortedMap_test.go +++ b/storage/txcache/maps/bucketSortedMap_test.go @@ -241,7 +241,7 @@ func TestBucketSortedMap_GetSnapshotAscending(t *testing.T) { myMap := NewBucketSortedMap(4, 100) snapshot := myMap.GetSnapshotAscending() - require.ElementsMatch(t, []BucketSortedMapItem{}, snapshot) + require.Equal(t, []BucketSortedMapItem{}, snapshot) a := newScoredDummyItem("a", 15) b := newScoredDummyItem("b", 101) @@ -256,14 +256,14 @@ func TestBucketSortedMap_GetSnapshotAscending(t *testing.T) { simulateMutationThatChangesScore(myMap, "c") snapshot = myMap.GetSnapshotAscending() - require.ElementsMatch(t, []BucketSortedMapItem{c, a, b}, snapshot) + require.Equal(t, []BucketSortedMapItem{c, a, b}, snapshot) } func TestBucketSortedMap_GetSnapshotDescending(t *testing.T) { myMap := NewBucketSortedMap(4, 100) snapshot := myMap.GetSnapshotDescending() - require.ElementsMatch(t, []BucketSortedMapItem{}, snapshot) + require.Equal(t, []BucketSortedMapItem{}, snapshot) a := newScoredDummyItem("a", 15) b := newScoredDummyItem("b", 101) @@ -278,7 +278,7 @@ func TestBucketSortedMap_GetSnapshotDescending(t *testing.T) { simulateMutationThatChangesScore(myMap, "c") snapshot = myMap.GetSnapshotDescending() - require.ElementsMatch(t, []BucketSortedMapItem{b, a, c}, snapshot) + require.Equal(t, []BucketSortedMapItem{b, a, c}, snapshot) } func TestBucketSortedMap_AddManyItems(t *testing.T) { diff --git a/storage/txcache/txCache_test.go b/storage/txcache/txCache_test.go index 507db7e375..a093a5a3d3 100644 --- a/storage/txcache/txCache_test.go +++ b/storage/txcache/txCache_test.go @@ -120,13 +120,13 @@ func Test_AddTx_AppliesSizeConstraintsPerSenderForNumTransactions(t *testing.T) cache.AddTx(createTx([]byte("tx-alice-4"), "alice", 4)) cache.AddTx(createTx([]byte("tx-bob-1"), "bob", 1)) cache.AddTx(createTx([]byte("tx-bob-2"), "bob", 2)) - require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) - require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.Equal(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) + require.Equal(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) require.True(t, cache.areInternalMapsConsistent()) cache.AddTx(createTx([]byte("tx-alice-3"), "alice", 3)) - require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) - require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.Equal(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) + require.Equal(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) require.True(t, cache.areInternalMapsConsistent()) } @@ -139,14 +139,14 @@ func Test_AddTx_AppliesSizeConstraintsPerSenderForNumBytes(t *testing.T) { cache.AddTx(createTxWithParams([]byte("tx-bob-1"), "bob", 1, 512, 42, 42)) cache.AddTx(createTxWithParams([]byte("tx-bob-2"), "bob", 2, 513, 42, 42)) - require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) - require.ElementsMatch(t, []string{"tx-bob-1"}, cache.getHashesForSender("bob")) + require.Equal(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-4"}, cache.getHashesForSender("alice")) + require.Equal(t, []string{"tx-bob-1"}, cache.getHashesForSender("bob")) require.True(t, cache.areInternalMapsConsistent()) cache.AddTx(createTxWithParams([]byte("tx-alice-3"), "alice", 3, 256, 42, 42)) cache.AddTx(createTxWithParams([]byte("tx-bob-2"), "bob", 3, 512, 42, 42)) - require.ElementsMatch(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) - require.ElementsMatch(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) + require.Equal(t, []string{"tx-alice-1", "tx-alice-2", "tx-alice-3"}, cache.getHashesForSender("alice")) + require.Equal(t, []string{"tx-bob-1", "tx-bob-2"}, cache.getHashesForSender("bob")) require.True(t, cache.areInternalMapsConsistent()) } diff --git a/storage/txcache/txListForSender.go b/storage/txcache/txListForSender.go index b6932b59ae..06152ce7da 100644 --- a/storage/txcache/txListForSender.go +++ b/storage/txcache/txListForSender.go @@ -114,21 +114,22 @@ func (listForSender *txListForSender) findInsertionPlace(incomingTx *WrappedTran incomingGasPrice := incomingTx.Tx.GetGasPrice() for element := listForSender.items.Back(); element != nil; element = element.Prev() { - tx := element.Value.(*WrappedTransaction) - nonce := tx.Tx.GetNonce() - gasPrice := tx.Tx.GetGasPrice() + currentTx := element.Value.(*WrappedTransaction) + currentTxNonce := currentTx.Tx.GetNonce() + currentTxGasPrice := currentTx.Tx.GetGasPrice() - if incomingTx.sameAs(tx) { + if incomingTx.sameAs(currentTx) { // The incoming transaction will be discarded return nil, errTxDuplicated } - if nonce == incomingNonce && gasPrice > incomingGasPrice { + if currentTxNonce == incomingNonce && currentTxGasPrice > incomingGasPrice { // The incoming transaction will be placed right after the existing one, which has same nonce but higher price. + // If the nonces are the same, but the incoming gas price is higher or equal, the search loop continues. return element, nil } - if nonce < incomingNonce { + if currentTxNonce < incomingNonce { // We've found the first transaction with a lower nonce than the incoming one, // thus the incoming transaction will be placed right after this one. return element, nil diff --git a/storage/txcache/txListForSender_test.go b/storage/txcache/txListForSender_test.go index a842a94679..76780ec02f 100644 --- a/storage/txcache/txListForSender_test.go +++ b/storage/txcache/txListForSender_test.go @@ -15,7 +15,7 @@ func TestListForSender_AddTx_Sorts(t *testing.T) { list.AddTx(createTx([]byte("d"), ".", 4)) list.AddTx(createTx([]byte("b"), ".", 2)) - require.ElementsMatch(t, []string{"a", "b", "c", "d"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"a", "b", "c", "d"}, list.getTxHashesAsStrings()) } func TestListForSender_AddTx_GivesPriorityToHigherGas(t *testing.T) { @@ -27,7 +27,22 @@ func TestListForSender_AddTx_GivesPriorityToHigherGas(t *testing.T) { list.AddTx(createTxWithParams([]byte("d"), ".", 2, 128, 42, 42)) list.AddTx(createTxWithParams([]byte("e"), ".", 3, 128, 42, 101)) - require.ElementsMatch(t, []string{"a", "d", "e", "b", "c"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"a", "d", "e", "b", "c"}, list.getTxHashesAsStrings()) +} + +func TestListForSender_AddTx_SortsCorrectlyWhenSameNonceSamePrice(t *testing.T) { + list := newUnconstrainedListToTest() + + list.AddTx(createTxWithParams([]byte("a"), ".", 1, 128, 42, 42)) + list.AddTx(createTxWithParams([]byte("b"), ".", 3, 128, 42, 100)) + list.AddTx(createTxWithParams([]byte("c"), ".", 3, 128, 42, 100)) + list.AddTx(createTxWithParams([]byte("d"), ".", 3, 128, 42, 98)) + list.AddTx(createTxWithParams([]byte("e"), ".", 3, 128, 42, 101)) + list.AddTx(createTxWithParams([]byte("f"), ".", 2, 128, 42, 42)) + list.AddTx(createTxWithParams([]byte("g"), ".", 3, 128, 42, 99)) + + // In case of same-nonce, same-price transactions, the newer one has priority + require.Equal(t, []string{"a", "f", "e", "c", "b", "g", "d"}, list.getTxHashesAsStrings()) } func TestListForSender_AddTx_IgnoresDuplicates(t *testing.T) { @@ -50,21 +65,21 @@ func TestListForSender_AddTx_AppliesSizeConstraintsForNumTransactions(t *testing list.AddTx(createTx([]byte("tx5"), ".", 5)) list.AddTx(createTx([]byte("tx4"), ".", 4)) list.AddTx(createTx([]byte("tx2"), ".", 2)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx4"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx1", "tx2", "tx4"}, list.getTxHashesAsStrings()) _, evicted := list.AddTx(createTx([]byte("tx3"), ".", 3)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx4"}, hashesAsStrings(evicted)) // Gives priority to higher gas - though undesirably to some extent, "tx3" is evicted _, evicted = list.AddTx(createTxWithParams([]byte("tx2++"), ".", 2, 128, 42, 42)) - require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx3"}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx3"}, hashesAsStrings(evicted)) // Though Undesirably to some extent, "tx3++"" is added, then evicted _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 3, 128, 42, 42)) - require.ElementsMatch(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx3++"}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2++", "tx2"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx3++"}, hashesAsStrings(evicted)) } func TestListForSender_AddTx_AppliesSizeConstraintsForNumBytes(t *testing.T) { @@ -74,21 +89,21 @@ func TestListForSender_AddTx_AppliesSizeConstraintsForNumBytes(t *testing.T) { list.AddTx(createTxWithParams([]byte("tx2"), ".", 2, 512, 42, 42)) list.AddTx(createTxWithParams([]byte("tx3"), ".", 3, 256, 42, 42)) _, evicted := list.AddTx(createTxWithParams([]byte("tx5"), ".", 4, 256, 42, 42)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx5"}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2", "tx3"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx5"}, hashesAsStrings(evicted)) _, evicted = list.AddTx(createTxWithParams([]byte("tx5--"), ".", 4, 128, 42, 42)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx3", "tx5--"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2", "tx3", "tx5--"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{}, hashesAsStrings(evicted)) _, evicted = list.AddTx(createTxWithParams([]byte("tx4"), ".", 4, 128, 42, 42)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx3", "tx4"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx5--"}, hashesAsStrings(evicted)) + require.Equal(t, []string{"tx1", "tx2", "tx3", "tx4"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx5--"}, hashesAsStrings(evicted)) // Gives priority to higher gas - though undesirably to some extent, "tx4" is evicted - _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 4, 256, 42, 100)) - require.ElementsMatch(t, []string{"tx1", "tx2", "tx3++", "tx3"}, list.getTxHashesAsStrings()) - require.ElementsMatch(t, []string{"tx4"}, hashesAsStrings(evicted)) + _, evicted = list.AddTx(createTxWithParams([]byte("tx3++"), ".", 3, 256, 42, 100)) + require.Equal(t, []string{"tx1", "tx2", "tx3++", "tx3"}, list.getTxHashesAsStrings()) + require.Equal(t, []string{"tx4"}, hashesAsStrings(evicted)) } func TestListForSender_findTx(t *testing.T) { From 9ca217c1febfc73e0298a0fd628e9b72a5ba12fc Mon Sep 17 00:00:00 2001 From: Sebastian Marian Date: Thu, 14 May 2020 14:40:41 +0300 Subject: [PATCH 61/79] Added go routines close mechanism through context and io.Close implementation for components: epochStartTrigger, txsPoolsCleaner, miniBlocksPoolsCleaner --- cmd/node/factory/structs.go | 8 +++- cmd/node/main.go | 2 +- consensus/chronology/chronology.go | 2 + consensus/interface.go | 3 +- consensus/mock/bootstrapMock.go | 8 ++-- consensus/mock/sposWorkerMock.go | 4 ++ consensus/mock/syncTimerMock.go | 4 +- consensus/spos/interface.go | 5 +-- consensus/spos/worker.go | 14 +++++-- consensus/spos/worker_test.go | 9 +++++ core/close/interface.go | 6 +++ epochStart/interface.go | 1 + epochStart/metachain/trigger.go | 7 ++++ epochStart/mock/syncTimerStub.go | 8 ++-- epochStart/shardchain/trigger.go | 36 ++++++++++++++++-- epochStart/shardchain/triggerRegistry_test.go | 1 + facade/mock/syncTimerMock.go | 8 ++-- integrationTests/consensus/testInitializer.go | 2 +- .../mock/endOfEpochTriggerStub.go | 5 +++ integrationTests/mock/syncTimerMock.go | 4 +- integrationTests/testProcessorNode.go | 2 +- node/mock/endOfEpochTriggerStub.go | 5 +++ node/mock/syncTimerStub.go | 4 +- node/node.go | 5 ++- ntp/interface.go | 5 +-- ntp/syncTime.go | 6 ++- ntp/syncTime_test.go | 4 +- .../poolsCleaner/miniBlocksPoolsCleaner.go | 38 +++++++++++++++++-- process/block/poolsCleaner/txsPoolsCleaner.go | 38 +++++++++++++++++-- process/interface.go | 12 ++++-- process/mock/endOfEpochTriggerStub.go | 5 +++ process/mock/syncTimerMock.go | 4 +- process/sync/baseSync.go | 3 ++ process/sync/metablock.go | 4 +- process/sync/metablock_test.go | 4 +- process/sync/shardblock.go | 4 +- process/sync/shardblock_test.go | 4 +- 37 files changed, 220 insertions(+), 64 deletions(-) create mode 100644 core/close/interface.go diff --git a/cmd/node/factory/structs.go b/cmd/node/factory/structs.go index dbeb987461..dddadc3348 100644 --- a/cmd/node/factory/structs.go +++ b/cmd/node/factory/structs.go @@ -345,7 +345,7 @@ func ProcessComponentsFactory(args *processComponentsFactoryArgs) (*Process, err return nil, err } - _, err = poolsCleaner.NewMiniBlocksPoolsCleaner( + mbsPoolsCleaner, err := poolsCleaner.NewMiniBlocksPoolsCleaner( args.data.Datapool.MiniBlocks(), args.rounder, args.shardCoordinator, @@ -354,7 +354,9 @@ func ProcessComponentsFactory(args *processComponentsFactoryArgs) (*Process, err return nil, err } - _, err = poolsCleaner.NewTxsPoolsCleaner( + mbsPoolsCleaner.StartCleaning() + + txsPoolsCleaner, err := poolsCleaner.NewTxsPoolsCleaner( args.state.AddressPubkeyConverter, args.data.Datapool, args.rounder, @@ -364,6 +366,8 @@ func ProcessComponentsFactory(args *processComponentsFactoryArgs) (*Process, err return nil, err } + txsPoolsCleaner.StartCleaning() + interceptorContainerFactory, blackListHandler, err := newInterceptorContainerFactory( args.shardCoordinator, args.nodesCoordinator, diff --git a/cmd/node/main.go b/cmd/node/main.go index 3fdff554be..9a44e15a35 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -603,7 +603,7 @@ func startNode(ctx *cli.Context, log logger.Logger, version string) error { log.Debug("config", "file", ctx.GlobalString(nodesFile.Name)) syncer := ntp.NewSyncTime(generalConfig.NTPConfig, nil) - syncer.StartSync() + syncer.StartSyncingTime() log.Debug("NTP average clock offset", "value", syncer.ClockOffset()) diff --git a/consensus/chronology/chronology.go b/consensus/chronology/chronology.go index d08e32760b..c5251d2744 100644 --- a/consensus/chronology/chronology.go +++ b/consensus/chronology/chronology.go @@ -10,12 +10,14 @@ import ( "github.com/ElrondNetwork/elrond-go/consensus" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/display" "github.com/ElrondNetwork/elrond-go/ntp" "github.com/ElrondNetwork/elrond-go/statusHandler" ) var _ consensus.ChronologyHandler = (*chronology)(nil) +var _ close.Closer = (*chronology)(nil) var log = logger.GetOrCreate("consensus/chronology") diff --git a/consensus/interface.go b/consensus/interface.go index bcf8b47358..2f45f37062 100644 --- a/consensus/interface.go +++ b/consensus/interface.go @@ -1,7 +1,6 @@ package consensus import ( - "io" "time" "github.com/ElrondNetwork/elrond-go/data" @@ -46,7 +45,7 @@ type SubroundHandler interface { // ChronologyHandler defines the actions which should be handled by a chronology implementation type ChronologyHandler interface { - io.Closer + Close() error AddSubround(SubroundHandler) RemoveAllSubrounds() // StartRounds starts rounds in a sequential manner, one after the other diff --git a/consensus/mock/bootstrapMock.go b/consensus/mock/bootstrapMock.go index a00b64c9af..1f0a768b29 100644 --- a/consensus/mock/bootstrapMock.go +++ b/consensus/mock/bootstrapMock.go @@ -11,7 +11,7 @@ type BootstrapperMock struct { CreateAndCommitEmptyBlockCalled func(uint32) (data.BodyHandler, data.HeaderHandler, error) AddSyncStateListenerCalled func(func(bool)) GetNodeStateCalled func() core.NodeState - StartSyncCalled func() + StartSyncingBlocksCalled func() SetStatusHandlerCalled func(handler core.AppStatusHandler) error } @@ -40,9 +40,9 @@ func (boot *BootstrapperMock) GetNodeState() core.NodeState { return core.NsSynchronized } -// StartSync - -func (boot *BootstrapperMock) StartSync() { - boot.StartSyncCalled() +// StartSyncingBlocks - +func (boot *BootstrapperMock) StartSyncingBlocks() { + boot.StartSyncingBlocksCalled() } // SetStatusHandler - diff --git a/consensus/mock/sposWorkerMock.go b/consensus/mock/sposWorkerMock.go index 0b834eaed1..e5bb8935a1 100644 --- a/consensus/mock/sposWorkerMock.go +++ b/consensus/mock/sposWorkerMock.go @@ -103,6 +103,10 @@ func (sposWorkerMock *SposWorkerMock) Close() error { return nil } +// StartWorking - +func (sposWorkerMock *SposWorkerMock) StartWorking() { +} + // IsInterfaceNil returns true if there is no value under the interface func (sposWorkerMock *SposWorkerMock) IsInterfaceNil() bool { return sposWorkerMock == nil diff --git a/consensus/mock/syncTimerMock.go b/consensus/mock/syncTimerMock.go index 12b9b8b949..2fa41d4234 100644 --- a/consensus/mock/syncTimerMock.go +++ b/consensus/mock/syncTimerMock.go @@ -10,8 +10,8 @@ type SyncTimerMock struct { CurrentTimeCalled func() time.Time } -// StartSync method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine -func (stm *SyncTimerMock) StartSync() { +// StartSyncingTime method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine +func (stm *SyncTimerMock) StartSyncingTime() { panic("implement me") } diff --git a/consensus/spos/interface.go b/consensus/spos/interface.go index 852851b68a..458b403c2e 100644 --- a/consensus/spos/interface.go +++ b/consensus/spos/interface.go @@ -1,8 +1,6 @@ package spos import ( - "io" - "github.com/ElrondNetwork/elrond-go/consensus" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/crypto" @@ -98,7 +96,8 @@ type SubroundsFactory interface { //WorkerHandler represents the interface for the SposWorker type WorkerHandler interface { - io.Closer + Close() error + StartWorking() //AddReceivedMessageCall adds a new handler function for a received message type AddReceivedMessageCall(messageType consensus.MessageType, receivedMessageCall func(cnsDta *consensus.Message) bool) //AddReceivedHeaderHandler adds a new handler function for a received header diff --git a/consensus/spos/worker.go b/consensus/spos/worker.go index cdcb1ca838..949e4baeef 100644 --- a/consensus/spos/worker.go +++ b/consensus/spos/worker.go @@ -10,6 +10,7 @@ import ( "github.com/ElrondNetwork/elrond-go/consensus" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/crypto" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/block" @@ -22,6 +23,8 @@ import ( "github.com/ElrondNetwork/elrond-go/statusHandler" ) +var _ close.Closer = (*Worker)(nil) + // Worker defines the data needed by spos to communicate between nodes which are in the validators group type Worker struct { consensusService ConsensusService @@ -139,16 +142,19 @@ func NewWorker(args *WorkerArgs) (*Worker, error) { maxMessagesInARoundPerPeer := wrk.consensusService.GetMaxMessagesInARoundPerPeer() wrk.antifloodHandler.SetMaxMessagesForTopic(topic, maxMessagesInARoundPerPeer) - var ctx context.Context - ctx, wrk.cancelFunc = context.WithCancel(context.Background()) - go wrk.checkChannels(ctx) - wrk.mapDisplayHashConsensusMessage = make(map[string][]*consensus.Message) wrk.publicKeyBitmapSize = wrk.getPublicKeyBitmapSize() return &wrk, nil } +// StartWorking actually starts the consensus working mechanism +func (wrk *Worker) StartWorking() { + var ctx context.Context + ctx, wrk.cancelFunc = context.WithCancel(context.Background()) + go wrk.checkChannels(ctx) +} + func checkNewWorkerParams( args *WorkerArgs, ) error { diff --git a/consensus/spos/worker_test.go b/consensus/spos/worker_test.go index 643e905be5..0f4ac1b8a8 100644 --- a/consensus/spos/worker_test.go +++ b/consensus/spos/worker_test.go @@ -1261,6 +1261,7 @@ func TestWorker_ExecuteSignatureMessagesShouldNotExecuteWhenBlockIsNotFinished(t func TestWorker_ExecuteMessagesShouldExecute(t *testing.T) { t.Parallel() wrk := *initWorker() + wrk.StartWorking() blk := &block.Body{} blkStr, _ := mock.MarshalizerMock{}.Marshal(blk) wrk.InitReceivedMessages() @@ -1286,11 +1287,14 @@ func TestWorker_ExecuteMessagesShouldExecute(t *testing.T) { wrk.ExecuteMessage(cnsDataList) assert.Nil(t, wrk.ReceivedMessages()[msgType][0]) + + wrk.Close() } func TestWorker_CheckChannelsShouldWork(t *testing.T) { t.Parallel() wrk := *initWorker() + wrk.StartWorking() wrk.SetReceivedMessagesCalls(bls.MtBlockHeader, func(cnsMsg *consensus.Message) bool { _ = wrk.ConsensusState().SetJobDone(wrk.ConsensusState().ConsensusGroup()[0], bls.SrBlock, true) return true @@ -1323,6 +1327,8 @@ func TestWorker_CheckChannelsShouldWork(t *testing.T) { assert.Nil(t, err) assert.True(t, isBlockJobDone) + + wrk.Close() } func TestWorker_ExtendShouldReturnWhenRoundIsCanceled(t *testing.T) { @@ -1429,6 +1435,7 @@ func TestWorker_ExtendShouldWork(t *testing.T) { func TestWorker_ExecuteStoredMessagesShouldWork(t *testing.T) { t.Parallel() wrk := *initWorker() + wrk.StartWorking() blk := &block.Body{} blkStr, _ := mock.MarshalizerMock{}.Marshal(blk) wrk.InitReceivedMessages() @@ -1459,6 +1466,8 @@ func TestWorker_ExecuteStoredMessagesShouldWork(t *testing.T) { rcvMsg = wrk.ReceivedMessages() assert.Equal(t, 0, len(rcvMsg[msgType])) + + wrk.Close() } func TestWorker_SetAppStatusHandlerNilShouldErr(t *testing.T) { diff --git a/core/close/interface.go b/core/close/interface.go new file mode 100644 index 0000000000..547c66c49d --- /dev/null +++ b/core/close/interface.go @@ -0,0 +1,6 @@ +package close + +// Closer closes all stuff released by an object +type Closer interface { + Close() error +} diff --git a/epochStart/interface.go b/epochStart/interface.go index 452ac1a099..7db41ca29f 100644 --- a/epochStart/interface.go +++ b/epochStart/interface.go @@ -11,6 +11,7 @@ import ( // TriggerHandler defines the functionalities for an start of epoch trigger type TriggerHandler interface { + Close() error ForceEpochStart(round uint64) error IsEpochStart() bool Epoch() uint32 diff --git a/epochStart/metachain/trigger.go b/epochStart/metachain/trigger.go index e1fa1febdf..dfe29df5fe 100644 --- a/epochStart/metachain/trigger.go +++ b/epochStart/metachain/trigger.go @@ -10,6 +10,7 @@ import ( "github.com/ElrondNetwork/elrond-go/config" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/dataRetriever" @@ -28,6 +29,7 @@ var _ dataRetriever.EpochHandler = (*trigger)(nil) var _ epochStart.TriggerHandler = (*trigger)(nil) var _ process.EpochStartTriggerHandler = (*trigger)(nil) var _ process.EpochBootstrapper = (*trigger)(nil) +var _ close.Closer = (*trigger)(nil) const minimumNonceToStartEpoch = 4 @@ -423,6 +425,11 @@ func (t *trigger) SetCurrentEpochStartRound(round uint64) { t.mutTrigger.Unlock() } +// Close will close the endless running go routine +func (t *trigger) Close() error { + return nil +} + // IsInterfaceNil return true if underlying object is nil func (t *trigger) IsInterfaceNil() bool { return t == nil diff --git a/epochStart/mock/syncTimerStub.go b/epochStart/mock/syncTimerStub.go index bb52303a94..8e9bb19c31 100644 --- a/epochStart/mock/syncTimerStub.go +++ b/epochStart/mock/syncTimerStub.go @@ -6,15 +6,15 @@ import ( // SyncTimerStub is a mock implementation of SyncTimer interface type SyncTimerStub struct { - StartSyncCalled func() + StartSyncingTimeCalled func() ClockOffsetCalled func() time.Duration FormattedCurrentTimeCalled func() string CurrentTimeCalled func() time.Time } -// StartSync is a mock implementation for StartSync -func (sts *SyncTimerStub) StartSync() { - sts.StartSyncCalled() +// StartSyncingTime is a mock implementation for StartSyncingTime +func (sts *SyncTimerStub) StartSyncingTime() { + sts.StartSyncingTimeCalled() } // ClockOffset is a mock implementation for ClockOffset diff --git a/epochStart/shardchain/trigger.go b/epochStart/shardchain/trigger.go index 6ddab642a2..6a09ddfa8e 100644 --- a/epochStart/shardchain/trigger.go +++ b/epochStart/shardchain/trigger.go @@ -2,6 +2,7 @@ package shardchain import ( "bytes" + "context" "fmt" "math" "sort" @@ -11,6 +12,7 @@ import ( "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/data/typeConverters" @@ -30,6 +32,7 @@ var _ dataRetriever.EpochHandler = (*trigger)(nil) var _ epochStart.TriggerHandler = (*trigger)(nil) var _ process.EpochStartTriggerHandler = (*trigger)(nil) var _ process.EpochBootstrapper = (*trigger)(nil) +var _ close.Closer = (*trigger)(nil) // sleepTime defines the time in milliseconds between each iteration made in requestMissingMiniblocks method const sleepTime = 1 * time.Second @@ -97,6 +100,7 @@ type trigger struct { mapMissingMiniblocks map[string]uint32 mutMissingMiniblocks sync.RWMutex + cancelFunc func() } type metaInfo struct { @@ -227,7 +231,10 @@ func NewEpochStartTrigger(args *ArgsShardEpochStartTrigger) (*trigger, error) { } t.mapMissingMiniblocks = make(map[string]uint32) - go t.requestMissingMiniblocks() + + var ctx context.Context + ctx, t.cancelFunc = context.WithCancel(context.Background()) + go t.requestMissingMiniblocks(ctx) return t, nil } @@ -243,9 +250,14 @@ func (t *trigger) clearMissingMiniblocksMap(epoch uint32) { } } -func (t *trigger) requestMissingMiniblocks() { +func (t *trigger) requestMissingMiniblocks(ctx context.Context) { for { - time.Sleep(sleepTime) + select { + case <-ctx.Done(): + log.Debug("trigger's go routine is stopping...") + return + case <-time.After(sleepTime): + } t.mutMissingMiniblocks.RLock() if len(t.mapMissingMiniblocks) == 0 { @@ -261,7 +273,14 @@ func (t *trigger) requestMissingMiniblocks() { t.mutMissingMiniblocks.RUnlock() go t.requestHandler.RequestMiniBlocks(core.MetachainShardId, missingMiniblocks) - time.Sleep(waitTime) + + select { + case <-ctx.Done(): + log.Debug("trigger's go routine is stopping...") + return + case <-time.After(waitTime): + } + t.updateMissingMiniblocks() } } @@ -918,6 +937,15 @@ func (t *trigger) saveCurrentState(round uint64) { } } +// Close will close the endless running go routine +func (t *trigger) Close() error { + if t.cancelFunc != nil { + t.cancelFunc() + } + + return nil +} + // IsInterfaceNil returns true if underlying object is nil func (t *trigger) IsInterfaceNil() bool { return t == nil diff --git a/epochStart/shardchain/triggerRegistry_test.go b/epochStart/shardchain/triggerRegistry_test.go index ccd2ed339c..d36c1df916 100644 --- a/epochStart/shardchain/triggerRegistry_test.go +++ b/epochStart/shardchain/triggerRegistry_test.go @@ -73,6 +73,7 @@ func TestTrigger_LoadStateAfterSave(t *testing.T) { epochStartTrigger1.epochMetaBlockHash = []byte("meta block hash") epochStartTrigger1.isEpochStart = false epochStartTrigger1.epochFinalityAttestingRound = 680 + epochStartTrigger1.cancelFunc = nil err := epochStartTrigger1.saveState(key) assert.Nil(t, err) assert.NotEqual(t, epochStartTrigger1, epochStartTrigger2) diff --git a/facade/mock/syncTimerMock.go b/facade/mock/syncTimerMock.go index 9d3ef9ca6a..b440600b7d 100644 --- a/facade/mock/syncTimerMock.go +++ b/facade/mock/syncTimerMock.go @@ -6,15 +6,15 @@ import ( // SyncTimerMock is a mock implementation of SyncTimer interface type SyncTimerMock struct { - StartSyncCalled func() + StartSyncingTimeCalled func() ClockOffsetCalled func() time.Duration FormattedCurrentTimeCalled func() string CurrentTimeCalled func() time.Time } -// StartSync is a mock implementation for StartSync -func (stm *SyncTimerMock) StartSync() { - stm.StartSyncCalled() +// StartSyncingTime is a mock implementation for StartSyncingTime +func (stm *SyncTimerMock) StartSyncingTime() { + stm.StartSyncingTimeCalled() } // ClockOffset is a mock implementation for ClockOffset diff --git a/integrationTests/consensus/testInitializer.go b/integrationTests/consensus/testInitializer.go index 9a29f1e562..4adf79c752 100644 --- a/integrationTests/consensus/testInitializer.go +++ b/integrationTests/consensus/testInitializer.go @@ -353,7 +353,7 @@ func createConsensusOnlyNode( singleBlsSigner := &mclsinglesig.BlsSingleSigner{} syncer := ntp.NewSyncTime(ntp.NewNTPGoogleConfig(), nil) - syncer.StartSync() + syncer.StartSyncingTime() rounder, _ := round.NewRound( time.Unix(startTime, 0), diff --git a/integrationTests/mock/endOfEpochTriggerStub.go b/integrationTests/mock/endOfEpochTriggerStub.go index f496e55561..6b8a806535 100644 --- a/integrationTests/mock/endOfEpochTriggerStub.go +++ b/integrationTests/mock/endOfEpochTriggerStub.go @@ -142,6 +142,11 @@ func (e *EpochStartTriggerStub) ReceivedHeader(header data.HeaderHandler) { func (e *EpochStartTriggerStub) SetRoundsPerEpoch(_ uint64) { } +// Close - +func (e *EpochStartTriggerStub) Close() error { + return nil +} + // IsInterfaceNil - func (e *EpochStartTriggerStub) IsInterfaceNil() bool { return e == nil diff --git a/integrationTests/mock/syncTimerMock.go b/integrationTests/mock/syncTimerMock.go index 12b9b8b949..2fa41d4234 100644 --- a/integrationTests/mock/syncTimerMock.go +++ b/integrationTests/mock/syncTimerMock.go @@ -10,8 +10,8 @@ type SyncTimerMock struct { CurrentTimeCalled func() time.Time } -// StartSync method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine -func (stm *SyncTimerMock) StartSync() { +// StartSyncingTime method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine +func (stm *SyncTimerMock) StartSyncingTime() { panic("implement me") } diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 255f586d7a..1dac195bf3 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -1409,7 +1409,7 @@ func (tpn *TestProcessorNode) StartSync() error { return errors.New("no bootstrapper available") } - tpn.Bootstrapper.StartSync() + tpn.Bootstrapper.StartSyncingBlocks() return nil } diff --git a/node/mock/endOfEpochTriggerStub.go b/node/mock/endOfEpochTriggerStub.go index f32afc7514..80d548ac30 100644 --- a/node/mock/endOfEpochTriggerStub.go +++ b/node/mock/endOfEpochTriggerStub.go @@ -121,6 +121,11 @@ func (e *EpochStartTriggerStub) MetaEpoch() uint32 { return 0 } +// Close - +func (e *EpochStartTriggerStub) Close() error { + return nil +} + // IsInterfaceNil - func (e *EpochStartTriggerStub) IsInterfaceNil() bool { return e == nil diff --git a/node/mock/syncTimerStub.go b/node/mock/syncTimerStub.go index dab1b237e2..b3d60be306 100644 --- a/node/mock/syncTimerStub.go +++ b/node/mock/syncTimerStub.go @@ -8,8 +8,8 @@ import ( type SyncTimerStub struct { } -// StartSync - -func (sts *SyncTimerStub) StartSync() { +// StartSyncingTime - +func (sts *SyncTimerStub) StartSyncingTime() { } // ClockOffset - diff --git a/node/node.go b/node/node.go index 4ab9d126e9..f623c7ffd3 100644 --- a/node/node.go +++ b/node/node.go @@ -240,7 +240,8 @@ func (n *Node) StartConsensus() error { log.Debug("cannot set app status handler for shard bootstrapper") } - bootstrapper.StartSync() + bootstrapper.StartSyncingBlocks() + epoch := uint32(0) crtBlockHeader := n.blkc.GetCurrentBlockHeader() if !check.IfNil(crtBlockHeader) { @@ -305,6 +306,8 @@ func (n *Node) StartConsensus() error { return err } + worker.StartWorking() + n.dataPool.Headers().RegisterHandler(worker.ReceivedHeader) err = n.createConsensusTopic(worker) diff --git a/ntp/interface.go b/ntp/interface.go index 5611846ab2..60b840c1d4 100644 --- a/ntp/interface.go +++ b/ntp/interface.go @@ -1,14 +1,13 @@ package ntp import ( - "io" "time" ) // SyncTimer defines an interface for time synchronization type SyncTimer interface { - io.Closer - StartSync() + Close() error + StartSyncingTime() ClockOffset() time.Duration FormattedCurrentTime() string CurrentTime() time.Time diff --git a/ntp/syncTime.go b/ntp/syncTime.go index 55b94798a3..a32ea484d7 100644 --- a/ntp/syncTime.go +++ b/ntp/syncTime.go @@ -13,10 +13,12 @@ import ( "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/config" "github.com/ElrondNetwork/elrond-go/core" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/beevik/ntp" ) var _ SyncTimer = (*syncTime)(nil) +var _ close.Closer = (*syncTime)(nil) var log = logger.GetOrCreate("ntp") @@ -120,9 +122,9 @@ func NewSyncTime( return &s } -// StartSync method does the time synchronization at every syncPeriod time elapsed. This method should be started on go +// StartSyncingTime method does the time synchronization at every syncPeriod time elapsed. This method should be started on go // routine -func (s *syncTime) StartSync() { +func (s *syncTime) StartSyncingTime() { var ctx context.Context ctx, s.cancelFunc = context.WithCancel(context.Background()) go s.startSync(ctx) diff --git a/ntp/syncTime_test.go b/ntp/syncTime_test.go index 0e103b7664..c6ca49fab4 100644 --- a/ntp/syncTime_test.go +++ b/ntp/syncTime_test.go @@ -130,7 +130,7 @@ func TestGetOffset(t *testing.T) { func TestCallQuery(t *testing.T) { st := ntp2.NewSyncTime(config.NTPConfig{Hosts: []string{""}, SyncPeriodSeconds: 1}, queryMock4) - st.StartSync() + st.StartSyncingTime() assert.NotNil(t, st.Query()) assert.Equal(t, time.Second, st.SyncPeriod()) @@ -144,6 +144,8 @@ func TestCallQuery(t *testing.T) { assert.NotEqual(t, qmc, 0) fmt.Printf("Current time: %v\n", st.FormattedCurrentTime()) + + st.Close() } func TestCallQueryShouldErrIndexOutOfBounds(t *testing.T) { diff --git a/process/block/poolsCleaner/miniBlocksPoolsCleaner.go b/process/block/poolsCleaner/miniBlocksPoolsCleaner.go index db3481ddd0..01c0be1236 100644 --- a/process/block/poolsCleaner/miniBlocksPoolsCleaner.go +++ b/process/block/poolsCleaner/miniBlocksPoolsCleaner.go @@ -1,11 +1,13 @@ package poolsCleaner import ( + "context" "sync" "time" "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/process" "github.com/ElrondNetwork/elrond-go/sharding" @@ -14,6 +16,8 @@ import ( var log = logger.GetOrCreate("process/block/poolsCleaner") +var _ close.Closer = (*miniBlocksPoolsCleaner)(nil) + type mbInfo struct { round int64 senderShardID uint32 @@ -29,6 +33,7 @@ type miniBlocksPoolsCleaner struct { mutMapMiniBlocksRounds sync.RWMutex mapMiniBlocksRounds map[string]*mbInfo + cancelFunc func() } // NewMiniBlocksPoolsCleaner will return a new miniblocks pools cleaner @@ -57,14 +62,25 @@ func NewMiniBlocksPoolsCleaner( mbpc.mapMiniBlocksRounds = make(map[string]*mbInfo) mbpc.miniblocksPool.RegisterHandler(mbpc.receivedMiniBlock) - go mbpc.cleanMiniblocksPools() - return &mbpc, nil } -func (mbpc *miniBlocksPoolsCleaner) cleanMiniblocksPools() { +// StartCleaning actually starts the pools cleaning mechanism +func (mbpc *miniBlocksPoolsCleaner) StartCleaning() { + var ctx context.Context + ctx, mbpc.cancelFunc = context.WithCancel(context.Background()) + go mbpc.cleanMiniblocksPools(ctx) +} + +func (mbpc *miniBlocksPoolsCleaner) cleanMiniblocksPools(ctx context.Context) { for { - time.Sleep(sleepTime) + select { + case <-ctx.Done(): + log.Debug("miniBlocksPoolsCleaner's go routine is stopping...") + return + case <-time.After(sleepTime): + } + numMiniblocksInMap := mbpc.cleanMiniblocksPoolsIfNeeded() log.Debug("miniBlocksPoolsCleaner.cleanMiniblocksPools", "num miniblocks in map", numMiniblocksInMap) } @@ -156,3 +172,17 @@ func (mbpc *miniBlocksPoolsCleaner) cleanMiniblocksPoolsIfNeeded() int { return len(mbpc.mapMiniBlocksRounds) } + +// Close will close the endless running go routine +func (mbpc *miniBlocksPoolsCleaner) Close() error { + if mbpc.cancelFunc != nil { + mbpc.cancelFunc() + } + + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (mbpc *miniBlocksPoolsCleaner) IsInterfaceNil() bool { + return mbpc == nil +} diff --git a/process/block/poolsCleaner/txsPoolsCleaner.go b/process/block/poolsCleaner/txsPoolsCleaner.go index bb254a4286..c4fa104d1f 100644 --- a/process/block/poolsCleaner/txsPoolsCleaner.go +++ b/process/block/poolsCleaner/txsPoolsCleaner.go @@ -2,11 +2,13 @@ package poolsCleaner import ( "bytes" + "context" "sync" "time" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/state" "github.com/ElrondNetwork/elrond-go/dataRetriever" @@ -16,6 +18,8 @@ import ( "github.com/ElrondNetwork/elrond-go/storage/txcache" ) +var _ close.Closer = (*txsPoolsCleaner)(nil) + // sleepTime defines the time between each iteration made in clean...Pools methods const sleepTime = time.Minute @@ -45,6 +49,7 @@ type txsPoolsCleaner struct { mutMapTxsRounds sync.RWMutex mapTxsRounds map[string]*txInfo emptyAddress []byte + cancelFunc func() } // NewTxsPoolsCleaner will return a new txs pools cleaner @@ -94,14 +99,25 @@ func NewTxsPoolsCleaner( tpc.emptyAddress = make([]byte, tpc.addressPubkeyConverter.Len()) - go tpc.cleanTxsPools() - return &tpc, nil } -func (tpc *txsPoolsCleaner) cleanTxsPools() { +// StartCleaning actually starts the pools cleaning mechanism +func (tpc *txsPoolsCleaner) StartCleaning() { + var ctx context.Context + ctx, tpc.cancelFunc = context.WithCancel(context.Background()) + go tpc.cleanTxsPools(ctx) +} + +func (tpc *txsPoolsCleaner) cleanTxsPools(ctx context.Context) { for { - time.Sleep(sleepTime) + select { + case <-ctx.Done(): + log.Debug("txsPoolsCleaner's go routine is stopping...") + return + case <-time.After(sleepTime): + } + numTxsInMap := tpc.cleanTxsPoolsIfNeeded() log.Debug("txsPoolsCleaner.cleanTxsPools", "num txs in map", numTxsInMap) } @@ -296,3 +312,17 @@ func (tpc *txsPoolsCleaner) getShardFromAddress(address []byte) (uint32, error) return tpc.shardCoordinator.ComputeId(address), nil } + +// Close will close the endless running go routine +func (tpc *txsPoolsCleaner) Close() error { + if tpc.cancelFunc != nil { + tpc.cancelFunc() + } + + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (tpc *txsPoolsCleaner) IsInterfaceNil() bool { + return tpc == nil +} diff --git a/process/interface.go b/process/interface.go index 2f989d8b52..8de80ba48c 100644 --- a/process/interface.go +++ b/process/interface.go @@ -1,7 +1,6 @@ package process import ( - "io" "math/big" "time" @@ -291,10 +290,10 @@ type HashAccesser interface { // Bootstrapper is an interface that defines the behaviour of a struct that is able // to synchronize the node type Bootstrapper interface { - io.Closer + Close() error AddSyncStateListener(func(isSyncing bool)) GetNodeState() core.NodeState - StartSync() + StartSyncingBlocks() SetStatusHandler(handler core.AppStatusHandler) error IsInterfaceNil() bool } @@ -836,3 +835,10 @@ type MiniblockAndHash struct { Miniblock *block.MiniBlock Hash []byte } + +// PoolsCleaner defines the functionality to clean pools for old records +type PoolsCleaner interface { + Close() error + StartCleaning() + IsInterfaceNil() bool +} diff --git a/process/mock/endOfEpochTriggerStub.go b/process/mock/endOfEpochTriggerStub.go index a5e5a124be..63a7433c4c 100644 --- a/process/mock/endOfEpochTriggerStub.go +++ b/process/mock/endOfEpochTriggerStub.go @@ -129,6 +129,11 @@ func (e *EpochStartTriggerStub) MetaEpoch() uint32 { return 0 } +// Close - +func (e *EpochStartTriggerStub) Close() error { + return nil +} + // IsInterfaceNil - func (e *EpochStartTriggerStub) IsInterfaceNil() bool { return e == nil diff --git a/process/mock/syncTimerMock.go b/process/mock/syncTimerMock.go index cb35ff7882..778b9fe3fa 100644 --- a/process/mock/syncTimerMock.go +++ b/process/mock/syncTimerMock.go @@ -10,8 +10,8 @@ type SyncTimerMock struct { CurrentTimeCalled func() time.Time } -// StartSync method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine -func (stm SyncTimerMock) StartSync() { +// StartSyncingTime method does the time synchronization at every syncPeriod time elapsed. This should be started as a go routine +func (stm SyncTimerMock) StartSyncingTime() { panic("implement me") } diff --git a/process/sync/baseSync.go b/process/sync/baseSync.go index 4400b076fb..46d82d2902 100644 --- a/process/sync/baseSync.go +++ b/process/sync/baseSync.go @@ -11,6 +11,7 @@ import ( "github.com/ElrondNetwork/elrond-go/consensus" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/close" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/data/state" @@ -26,6 +27,8 @@ import ( var log = logger.GetOrCreate("process/sync") +var _ close.Closer = (*baseBootstrap)(nil) + // sleepTime defines the time in milliseconds between each iteration made in syncBlocks method const sleepTime = 5 * time.Millisecond diff --git a/process/sync/metablock.go b/process/sync/metablock.go index 3f4188d6dd..3341126714 100644 --- a/process/sync/metablock.go +++ b/process/sync/metablock.go @@ -104,8 +104,8 @@ func (boot *MetaBootstrap) getBlockBody(headerHandler data.HeaderHandler) (data. return &block.Body{MiniBlocks: miniBlocks}, nil } -// StartSync method will start SyncBlocks as a go routine -func (boot *MetaBootstrap) StartSync() { +// StartSyncingBlocks method will start syncing blocks as a go routine +func (boot *MetaBootstrap) StartSyncingBlocks() { // when a node starts it first tries to bootstrap from storage, if there already exist a database saved errNotCritical := boot.storageBootstrapper.LoadFromStorage() if errNotCritical != nil { diff --git a/process/sync/metablock_test.go b/process/sync/metablock_test.go index 7f02c09ecc..a8a490a7c5 100644 --- a/process/sync/metablock_test.go +++ b/process/sync/metablock_test.go @@ -371,7 +371,7 @@ func TestMetaBootstrap_ShouldNotNeedToSync(t *testing.T) { bs, _ := sync.NewMetaBootstrap(args) - bs.StartSync() + bs.StartSyncingBlocks() time.Sleep(200 * time.Millisecond) bs.Close() } @@ -442,7 +442,7 @@ func TestMetaBootstrap_SyncShouldSyncOneBlock(t *testing.T) { ) bs, _ := sync.NewMetaBootstrap(args) - bs.StartSync() + bs.StartSyncingBlocks() time.Sleep(200 * time.Millisecond) diff --git a/process/sync/shardblock.go b/process/sync/shardblock.go index 3e29a33038..54222716f8 100644 --- a/process/sync/shardblock.go +++ b/process/sync/shardblock.go @@ -101,8 +101,8 @@ func (boot *ShardBootstrap) getBlockBody(headerHandler data.HeaderHandler) (data return &block.Body{MiniBlocks: miniBlocks}, nil } -// StartSync method will start SyncBlocks as a go routine -func (boot *ShardBootstrap) StartSync() { +// StartSyncingBlocks method will start syncing blocks as a go routine +func (boot *ShardBootstrap) StartSyncingBlocks() { errNotCritical := boot.storageBootstrapper.LoadFromStorage() if errNotCritical != nil { log.Debug("boot.syncFromStorer", diff --git a/process/sync/shardblock_test.go b/process/sync/shardblock_test.go index b6694895d7..0c5379c83a 100644 --- a/process/sync/shardblock_test.go +++ b/process/sync/shardblock_test.go @@ -585,7 +585,7 @@ func TestBootstrap_ShouldNotNeedToSync(t *testing.T) { bs, _ := sync.NewShardBootstrap(args) - bs.StartSync() + bs.StartSyncingBlocks() time.Sleep(200 * time.Millisecond) bs.Close() } @@ -675,7 +675,7 @@ func TestBootstrap_SyncShouldSyncOneBlock(t *testing.T) { ) bs, _ := sync.NewShardBootstrap(args) - bs.StartSync() + bs.StartSyncingBlocks() time.Sleep(200 * time.Millisecond) From 9253c854c304679099ce34602e24fe96c1ae960d Mon Sep 17 00:00:00 2001 From: Sebastian Marian Date: Thu, 14 May 2020 14:42:52 +0300 Subject: [PATCH 62/79] * Added a constant for wait time between each iteration made in method checkChannels from Worker --- consensus/spos/worker.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/consensus/spos/worker.go b/consensus/spos/worker.go index 949e4baeef..d7ed1a1ffc 100644 --- a/consensus/spos/worker.go +++ b/consensus/spos/worker.go @@ -25,6 +25,9 @@ import ( var _ close.Closer = (*Worker)(nil) +// sleepTime defines the time in milliseconds between each iteration made in checkChannels method +const sleepTime = 5 * time.Millisecond + // Worker defines the data needed by spos to communicate between nodes which are in the validators group type Worker struct { consensusService ConsensusService @@ -559,7 +562,7 @@ func (wrk *Worker) checkChannels(ctx context.Context) { log.Debug("worker's go routine is stopping...") return case rcvDta = <-wrk.executeMessageChannel: - case <-time.After(time.Millisecond): + case <-time.After(sleepTime): continue } From 3f6bdb7b27116e2b43c612f35ae6d2e13afd67e1 Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Thu, 14 May 2020 15:41:35 +0300 Subject: [PATCH 63/79] get rewards txs from pool before commitEpochStart method also modify gasUsed now is measured in gas units --- core/indexer/common.go | 15 ++++----------- core/indexer/data.go | 2 +- core/indexer/elasticsearchDatabase_test.go | 22 +++++++++++++++++++--- core/indexer/processTransactions.go | 9 ++++----- core/indexer/processTransactions_test.go | 10 ++++++++-- process/block/metablock.go | 5 +++-- 6 files changed, 39 insertions(+), 24 deletions(-) diff --git a/core/indexer/common.go b/core/indexer/common.go index 0aa97bfd1e..ebf286aed6 100644 --- a/core/indexer/common.go +++ b/core/indexer/common.go @@ -140,10 +140,6 @@ func (cm *commonProcessor) buildTransaction( header data.HeaderHandler, txStatus string, ) *Transaction { - gasPriceBig := big.NewInt(0).SetUint64(tx.GasPrice) - gasLimitBig := big.NewInt(0).SetUint64(tx.GasLimit) - gasUsed := big.NewInt(0).Mul(gasPriceBig, gasLimitBig).String() - return &Transaction{ Hash: hex.EncodeToString(txHash), MBHash: hex.EncodeToString(mbHash), @@ -160,7 +156,7 @@ func (cm *commonProcessor) buildTransaction( Signature: hex.EncodeToString(tx.Signature), Timestamp: time.Duration(header.GetTimeStamp()), Status: txStatus, - GasUsed: gasUsed, + GasUsed: tx.GasLimit, } } @@ -354,17 +350,14 @@ func prepareTxUpdate(tx *Transaction) ([]byte, []byte) { return nil, nil } - gasPriceBig := big.NewInt(0).SetUint64(tx.GasPrice) - gasLimitBig := big.NewInt(0).SetUint64(tx.GasLimit) - gas := big.NewInt(0).Mul(gasPriceBig, gasLimitBig).String() - if tx.GasUsed == gas { + if tx.GasUsed == tx.GasLimit { // do not update gasUsed because it is the same with gasUsed when transaction was saved first time in database serializedData = []byte(fmt.Sprintf(`{ "doc" : { "log" : %s, "scResults" : %s, "status": "%s", "timestamp": %s } }`, string(marshalizedLog), string(scResults), tx.Status, string(marshalizedTimestamp))) } else { // update gasUsed because was changed (is a smart contract operation) - serializedData = []byte(fmt.Sprintf(`{ "doc" : { "log" : %s, "scResults" : %s, "status": "%s", "timestamp": %s, "gasUsed" : "%s" } }`, - string(marshalizedLog), string(scResults), tx.Status, string(marshalizedTimestamp), tx.GasUsed)) + serializedData = []byte(fmt.Sprintf(`{ "doc" : { "log" : %s, "scResults" : %s, "status": "%s", "timestamp": %s, "gasUsed" : %s } }`, + string(marshalizedLog), string(scResults), tx.Status, string(marshalizedTimestamp), fmt.Sprintf("%d", tx.GasUsed))) } return meta, serializedData diff --git a/core/indexer/data.go b/core/indexer/data.go index 3fcf093ce8..c18a2fc25a 100644 --- a/core/indexer/data.go +++ b/core/indexer/data.go @@ -21,11 +21,11 @@ type Transaction struct { SenderShard uint32 `json:"senderShard"` GasPrice uint64 `json:"gasPrice"` GasLimit uint64 `json:"gasLimit"` + GasUsed uint64 `json:"gasUsed"` Data string `json:"data"` Signature string `json:"signature"` Timestamp time.Duration `json:"timestamp"` Status string `json:"status"` - GasUsed string `json:"gasUsed"` SmartContractResults []ScResult `json:"scResults"` Log TxLog `json:"-"` } diff --git a/core/indexer/elasticsearchDatabase_test.go b/core/indexer/elasticsearchDatabase_test.go index 548bfb4f85..6038e23548 100644 --- a/core/indexer/elasticsearchDatabase_test.go +++ b/core/indexer/elasticsearchDatabase_test.go @@ -20,6 +20,7 @@ import ( "github.com/ElrondNetwork/elrond-go/data" dataBlock "github.com/ElrondNetwork/elrond-go/data/block" "github.com/ElrondNetwork/elrond-go/data/receipt" + "github.com/ElrondNetwork/elrond-go/data/rewardTx" "github.com/ElrondNetwork/elrond-go/data/smartContractResult" "github.com/ElrondNetwork/elrond-go/data/transaction" "github.com/elastic/go-elasticsearch/v7/esapi" @@ -387,14 +388,14 @@ func TestUpdateTransaction(t *testing.T) { txHash1 := []byte("txHash1") tx1 := &transaction.Transaction{ - GasPrice: 1, + GasPrice: 10, GasLimit: 500, } txHash2 := []byte("txHash2") sndAddr := []byte("snd") tx2 := &transaction.Transaction{ - GasLimit: 1, - GasPrice: 500, + GasPrice: 10, + GasLimit: 500, SndAddr: sndAddr, } txHash3 := []byte("txHash3") @@ -420,6 +421,15 @@ func TestUpdateTransaction(t *testing.T) { Value: big.NewInt(150), } + rTx1Hash := []byte("rTxHash1") + rTx1 := &rewardTx.RewardTx{ + Round: 1113, + } + rTx2Hash := []byte("rTxHash2") + rTx2 := &rewardTx.RewardTx{ + Round: 1114, + } + body := &dataBlock.Body{ MiniBlocks: []*dataBlock.MiniBlock{ { @@ -430,6 +440,10 @@ func TestUpdateTransaction(t *testing.T) { TxHashes: [][]byte{txHash3}, Type: dataBlock.TxBlock, }, + { + Type: dataBlock.RewardsBlock, + TxHashes: [][]byte{rTx1Hash, rTx2Hash}, + }, { TxHashes: [][]byte{recHash1}, Type: dataBlock.ReceiptBlock, @@ -446,6 +460,8 @@ func TestUpdateTransaction(t *testing.T) { string(txHash2): tx2, string(txHash3): tx3, string(recHash1): rec1, + string(rTx1Hash): rTx1, + string(rTx2Hash): rTx2, } body.MiniBlocks[0].ReceiverShardID = 1 diff --git a/core/indexer/processTransactions.go b/core/indexer/processTransactions.go index 99816ac309..57c2d03657 100644 --- a/core/indexer/processTransactions.go +++ b/core/indexer/processTransactions.go @@ -69,8 +69,9 @@ func (tdp *txDatabaseProcessor) prepareTransactionsForDatabase( gasUsed := big.NewInt(0).SetUint64(tx.GasPrice) gasUsed.Mul(gasUsed, big.NewInt(0).SetUint64(tx.GasLimit)) gasUsed.Sub(gasUsed, rec.Value) + gasUsed.Div(gasUsed, big.NewInt(0).SetUint64(tx.GasPrice)) - tx.GasUsed = gasUsed.String() + tx.GasUsed = gasUsed.Uint64() } countScResults := make(map[string]int) @@ -116,10 +117,8 @@ func (tdp *txDatabaseProcessor) addScResultInfoInTx(scr *smartContractResult.Sma tx.SmartContractResults = append(tx.SmartContractResults, dbScResult) if dbScResult.GasLimit != 0 && dbScResult.Value != "0" { - gasUsed := big.NewInt(0).SetUint64(tx.GasPrice) - gasUsed.Mul(gasUsed, big.NewInt(0).SetUint64(tx.GasLimit)) - gasUsed.Sub(gasUsed, scr.Value) - tx.GasUsed = gasUsed.String() + gasUsed := tx.GasLimit - scr.GasLimit + tx.GasUsed = gasUsed } return tx diff --git a/core/indexer/processTransactions_test.go b/core/indexer/processTransactions_test.go index 803f0117f7..067a99d338 100644 --- a/core/indexer/processTransactions_test.go +++ b/core/indexer/processTransactions_test.go @@ -19,9 +19,15 @@ func TestPrepareTransactionsForDatabase(t *testing.T) { t.Parallel() txHash1 := []byte("txHash1") - tx1 := &transaction.Transaction{} + tx1 := &transaction.Transaction{ + GasLimit: 100, + GasPrice: 100, + } txHash2 := []byte("txHash2") - tx2 := &transaction.Transaction{} + tx2 := &transaction.Transaction{ + GasLimit: 100, + GasPrice: 100, + } txHash3 := []byte("txHash3") tx3 := &transaction.Transaction{} txHash4 := []byte("txHash4") diff --git a/process/block/metablock.go b/process/block/metablock.go index 6fd005ff5a..d766396871 100644 --- a/process/block/metablock.go +++ b/process/block/metablock.go @@ -1003,6 +1003,9 @@ func (mp *metaProcessor) CommitBlock( return err } + // must be called before commitEpochStart + rewardsTxs := mp.getRewardsTxs(header, body) + mp.commitEpochStart(header, body) headerHash := mp.hasher.Compute(string(marshalizedHeader)) mp.saveMetaHeader(header, headerHash, marshalizedHeader) @@ -1013,8 +1016,6 @@ func (mp *metaProcessor) CommitBlock( return err } - rewardsTxs := mp.getRewardsTxs(header, body) - mp.validatorStatisticsProcessor.DisplayRatings(header.GetEpoch()) err = mp.saveLastNotarizedHeader(header) From 036e8fc880377e891e21052b390cec89395216a6 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Thu, 14 May 2020 22:05:23 +0300 Subject: [PATCH 64/79] - integrated new delegation SC in genesis processing - modified unit test to be a sort-of fast running integration test - added verify process after delegation call to make sure the contract has the correct state --- data/state/accountsDB.go | 5 + genesis/data/initialSmartContract.go | 11 + genesis/data/initialSmartContract_test.go | 11 + genesis/errors.go | 16 +- genesis/interface.go | 4 +- genesis/mock/deployProcessorStub.go | 7 - genesis/mock/queryServiceStub.go | 36 ++ genesis/mock/shardCoordinatorMock.go | 2 +- genesis/mock/txExecutionProcessorStub.go | 10 + genesis/process/argGenesisBlockCreator.go | 7 +- .../process/baseGenesisProcessorsFactory.go | 2 + genesis/process/genesisBlockCreator.go | 7 + genesis/process/genesisBlockCreator_test.go | 79 ++-- .../intermediate/delegationDeployProcessor.go | 85 ---- .../delegationDeployProcessor_test.go | 158 ------- .../intermediate/delegationProcessor.go | 402 ++++++++++++++---- .../intermediate/delegationProcessor_test.go | 295 ++++++++----- .../process/intermediate/deployProcessor.go | 70 +-- .../intermediate/deployProcessor_test.go | 30 +- .../intermediate/txExecutionProcessor.go | 7 + genesis/process/intermediate/variables.go | 5 + genesis/process/metaGenesisBlockCreator.go | 16 +- genesis/process/shardGenesisBlockCreator.go | 34 +- genesis/process/testdata/delegation.wasm | Bin 0 -> 52245 bytes genesis/process/testdata/genesis.json | 18 +- genesis/process/testdata/smartcontracts.json | 11 +- 26 files changed, 769 insertions(+), 559 deletions(-) create mode 100644 genesis/mock/queryServiceStub.go delete mode 100644 genesis/process/intermediate/delegationDeployProcessor.go delete mode 100644 genesis/process/intermediate/delegationDeployProcessor_test.go create mode 100644 genesis/process/intermediate/variables.go create mode 100755 genesis/process/testdata/delegation.wasm diff --git a/data/state/accountsDB.go b/data/state/accountsDB.go index 045da0fcbe..4d304da82f 100644 --- a/data/state/accountsDB.go +++ b/data/state/accountsDB.go @@ -227,6 +227,11 @@ func (adb *AccountsDB) saveDataTrie(accountHandler baseAccountHandler) error { accountHandler.SetRootHash(rootHash) trackableDataTrie.ClearDataCaches() + log.Trace("accountsDB.SaveDataTrie", + "address", hex.EncodeToString(accountHandler.AddressBytes()), + "new root hash", accountHandler.GetRootHash(), + ) + return nil } diff --git a/genesis/data/initialSmartContract.go b/genesis/data/initialSmartContract.go index 96a7861603..50342a66b0 100644 --- a/genesis/data/initialSmartContract.go +++ b/genesis/data/initialSmartContract.go @@ -10,6 +10,7 @@ type InitialSmartContract struct { ownerBytes []byte vmTypeBytes []byte addressBytes []byte + address string } // OwnerBytes will return the owner's address as raw bytes @@ -67,6 +68,16 @@ func (isc *InitialSmartContract) AddressBytes() []byte { return isc.addressBytes } +// SetAddress sets the initial smart contract address as string +func (isc *InitialSmartContract) SetAddress(address string) { + isc.address = address +} + +// Address returns the smart contract address string +func (isc *InitialSmartContract) Address() string { + return isc.address +} + // IsInterfaceNil returns if underlying object is true func (isc *InitialSmartContract) IsInterfaceNil() bool { return isc == nil diff --git a/genesis/data/initialSmartContract_test.go b/genesis/data/initialSmartContract_test.go index e4c3ae7bf2..34b3c2db4b 100644 --- a/genesis/data/initialSmartContract_test.go +++ b/genesis/data/initialSmartContract_test.go @@ -63,3 +63,14 @@ func TestInitialSmartContract_AddressBytes(t *testing.T) { assert.Equal(t, addrBytes, recoverdAddrBytes) } + +func TestInitialSmartContract_Address(t *testing.T) { + t.Parallel() + + ia := &InitialSmartContract{} + address := "address" + ia.SetAddress(address) + recoverdAddress := ia.Address() + + assert.Equal(t, address, recoverdAddress) +} diff --git a/genesis/errors.go b/genesis/errors.go index a8404f64e7..bb65be3f6b 100644 --- a/genesis/errors.go +++ b/genesis/errors.go @@ -113,8 +113,20 @@ var ErrNilNodesListSplitter = errors.New("nil nodes list splitter") // ErrNilNodesSetup signals that a nil nodes setup handler has been provided var ErrNilNodesSetup = errors.New("nil nodes setup") -// ErrNilDeployProcessor signals that a nil deploy processor has been provided -var ErrNilDeployProcessor = errors.New("nil deploy processor") +// ErrAccountAlreadyExists signals that an account already exists +var ErrAccountAlreadyExists = errors.New("account already exists") + +// ErrAccountNotCreated signals that an account could not have been created +var ErrAccountNotCreated = errors.New("account not created") // ErrNilTrieStorageManager signals that a nil trie storage manager has been provided var ErrNilTrieStorageManager = errors.New("nil trie storage manager") + +// ErrWhileVerifyingDelegation signals that a verification error occurred +var ErrWhileVerifyingDelegation = errors.New("error occurred while verifying delegation SC") + +// ErrNilQueryService signals that a nil query service has been provided +var ErrNilQueryService = errors.New("nil query service") + +// ErrMissingElement signals a missing element event +var ErrMissingElement = errors.New("missing element") diff --git a/genesis/interface.go b/genesis/interface.go index ca3f383883..5b3789248a 100644 --- a/genesis/interface.go +++ b/genesis/interface.go @@ -62,6 +62,8 @@ type InitialSmartContractHandler interface { VmTypeBytes() []byte SetAddressBytes(addressBytes []byte) AddressBytes() []byte + SetAddress(address string) + Address() string IsInterfaceNil() bool } @@ -76,6 +78,7 @@ type InitialSmartContractParser interface { // TxExecutionProcessor represents a transaction builder and executor containing also related helper functions type TxExecutionProcessor interface { ExecuteTransaction(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error + AccountExists(address []byte) bool GetNonce(senderBytes []byte) (uint64, error) AddBalance(senderBytes []byte, value *big.Int) error AddNonce(senderBytes []byte, nonce uint64) error @@ -92,6 +95,5 @@ type NodesListSplitter interface { // DeployProcessor is able to deploy a smart contract type DeployProcessor interface { Deploy(sc InitialSmartContractHandler) error - SetReplacePlaceholders(handler func(txData string, scResultingAddressBytes []byte) (string, error)) IsInterfaceNil() bool } diff --git a/genesis/mock/deployProcessorStub.go b/genesis/mock/deployProcessorStub.go index 44d1dfbf9e..d9a1f0bc07 100644 --- a/genesis/mock/deployProcessorStub.go +++ b/genesis/mock/deployProcessorStub.go @@ -17,13 +17,6 @@ func (dps *DeployProcessorStub) Deploy(sc genesis.InitialSmartContractHandler) e return nil } -// SetReplacePlaceholders - -func (dps *DeployProcessorStub) SetReplacePlaceholders(handler func(txData string, scResultingAddressBytes []byte) (string, error)) { - if dps.SetReplacePlaceholdersCalled != nil { - dps.SetReplacePlaceholdersCalled(handler) - } -} - // IsInterfaceNil - func (dps *DeployProcessorStub) IsInterfaceNil() bool { return dps == nil diff --git a/genesis/mock/queryServiceStub.go b/genesis/mock/queryServiceStub.go new file mode 100644 index 0000000000..66a3a88b88 --- /dev/null +++ b/genesis/mock/queryServiceStub.go @@ -0,0 +1,36 @@ +package mock + +import ( + "github.com/ElrondNetwork/elrond-go/data/transaction" + "github.com/ElrondNetwork/elrond-go/process" + vmcommon "github.com/ElrondNetwork/elrond-vm-common" +) + +// QueryServiceStub - +type QueryServiceStub struct { + ComputeScCallGasLimitCalled func(tx *transaction.Transaction) (uint64, error) + ExecuteQueryCalled func(query *process.SCQuery) (*vmcommon.VMOutput, error) +} + +// ComputeScCallGasLimit - +func (qss *QueryServiceStub) ComputeScCallGasLimit(tx *transaction.Transaction) (uint64, error) { + if qss.ComputeScCallGasLimitCalled != nil { + return qss.ComputeScCallGasLimitCalled(tx) + } + + return 0, nil +} + +// ExecuteQuery - +func (qss *QueryServiceStub) ExecuteQuery(query *process.SCQuery) (*vmcommon.VMOutput, error) { + if qss.ExecuteQueryCalled != nil { + return qss.ExecuteQueryCalled(query) + } + + return &vmcommon.VMOutput{}, nil +} + +// IsInterfaceNil - +func (qss *QueryServiceStub) IsInterfaceNil() bool { + return qss == nil +} diff --git a/genesis/mock/shardCoordinatorMock.go b/genesis/mock/shardCoordinatorMock.go index 77cd9928b9..65681981ec 100644 --- a/genesis/mock/shardCoordinatorMock.go +++ b/genesis/mock/shardCoordinatorMock.go @@ -61,7 +61,7 @@ func (scm *ShardCoordinatorMock) SameShard(address1, address2 []byte) bool { return false } - return address1[len(address1)-1] == address2[len(address2)-1] + return scm.ComputeId(address1) == scm.ComputeId(address2) } // CommunicationIdentifier - diff --git a/genesis/mock/txExecutionProcessorStub.go b/genesis/mock/txExecutionProcessorStub.go index 606c6bca6b..be3bd1982c 100644 --- a/genesis/mock/txExecutionProcessorStub.go +++ b/genesis/mock/txExecutionProcessorStub.go @@ -5,6 +5,7 @@ import "math/big" // TxExecutionProcessorStub - type TxExecutionProcessorStub struct { ExecuteTransactionCalled func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error + AccountExistsCalled func(address []byte) bool GetNonceCalled func(senderBytes []byte) (uint64, error) AddBalanceCalled func(senderBytes []byte, value *big.Int) error AddNonceCalled func(senderBytes []byte, nonce uint64) error @@ -19,6 +20,15 @@ func (teps *TxExecutionProcessorStub) ExecuteTransaction(nonce uint64, sndAddr [ return nil } +// AccountExists - +func (teps *TxExecutionProcessorStub) AccountExists(address []byte) bool { + if teps.AccountExistsCalled != nil { + return teps.AccountExistsCalled(address) + } + + return false +} + // GetNonce - func (teps *TxExecutionProcessorStub) GetNonce(senderBytes []byte) (uint64, error) { if teps.GetNonceCalled != nil { diff --git a/genesis/process/argGenesisBlockCreator.go b/genesis/process/argGenesisBlockCreator.go index 3b9430241b..a5eb879524 100644 --- a/genesis/process/argGenesisBlockCreator.go +++ b/genesis/process/argGenesisBlockCreator.go @@ -37,9 +37,10 @@ type ArgsGenesisBlockCreator struct { TxLogsProcessor process.TransactionLogProcessor VirtualMachineConfig config.VirtualMachineConfig HardForkConfig config.HardforkConfig - TrieStorageManagers map[string]data.StorageManager - ChainID string - SystemSCConfig config.SystemSmartContractsConfig + //TODO remove this: at genesis time the genesis block creator should not write other shard's data in the same storage manager + TrieStorageManagers map[string]data.StorageManager + ChainID string + SystemSCConfig config.SystemSmartContractsConfig // created component needed only for hardfork importHandler update.ImportHandler diff --git a/genesis/process/baseGenesisProcessorsFactory.go b/genesis/process/baseGenesisProcessorsFactory.go index 501a087d91..82979839e1 100644 --- a/genesis/process/baseGenesisProcessorsFactory.go +++ b/genesis/process/baseGenesisProcessorsFactory.go @@ -1,6 +1,7 @@ package process import ( + "github.com/ElrondNetwork/elrond-go/node/external" "github.com/ElrondNetwork/elrond-go/process" "github.com/ElrondNetwork/elrond-go/vm" ) @@ -13,4 +14,5 @@ type genesisProcessors struct { scrProcessor process.SmartContractResultProcessor rwdProcessor process.RewardTransactionProcessor blockchainHook process.BlockChainHookHandler + queryService external.SCQueryService } diff --git a/genesis/process/genesisBlockCreator.go b/genesis/process/genesisBlockCreator.go index 4ea15ec020..e73b0d65c0 100644 --- a/genesis/process/genesisBlockCreator.go +++ b/genesis/process/genesisBlockCreator.go @@ -169,6 +169,9 @@ func (gbc *genesisBlockCreator) CreateGenesisBlocks() (map[uint32]data.HeaderHan } for shardID := uint32(0); shardID < gbc.arg.ShardCoordinator.NumberOfShards(); shardID++ { + log.Debug("genesis block creator", + "shard ID", shardID, + ) newArgument, err = gbc.getNewArgForShard(shardID) if err != nil { return nil, fmt.Errorf("'%w' while creating new argument for shard %d", @@ -189,6 +192,10 @@ func (gbc *genesisBlockCreator) CreateGenesisBlocks() (map[uint32]data.HeaderHan } } + log.Debug("genesis block creator", + "shard ID", "meta", + ) + newArgument, err = gbc.getNewArgForShard(core.MetachainShardId) if err != nil { return nil, fmt.Errorf("'%w' while creating new argument for metachain", err) diff --git a/genesis/process/genesisBlockCreator_test.go b/genesis/process/genesisBlockCreator_test.go index 65f8de8e6f..944ab6371e 100644 --- a/genesis/process/genesisBlockCreator_test.go +++ b/genesis/process/genesisBlockCreator_test.go @@ -1,6 +1,9 @@ package process import ( + "bytes" + "encoding/hex" + "math" "math/big" "testing" @@ -8,23 +11,27 @@ import ( "github.com/ElrondNetwork/elrond-go/config" "github.com/ElrondNetwork/elrond-go/data" "github.com/ElrondNetwork/elrond-go/data/state" + factoryState "github.com/ElrondNetwork/elrond-go/data/state/factory" + "github.com/ElrondNetwork/elrond-go/data/trie" "github.com/ElrondNetwork/elrond-go/data/trie/factory" "github.com/ElrondNetwork/elrond-go/dataRetriever" "github.com/ElrondNetwork/elrond-go/genesis/mock" "github.com/ElrondNetwork/elrond-go/genesis/parsing" "github.com/ElrondNetwork/elrond-go/process/economics" + "github.com/ElrondNetwork/elrond-go/sharding" "github.com/ElrondNetwork/elrond-go/storage" "github.com/ElrondNetwork/elrond-go/vm/systemSmartContracts/defaults" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +var entireGenesisSupply = big.NewInt(22000) +var nodePrice = big.NewInt(5000) + //TODO improve code coverage of this package -func createMockArgument() ArgsGenesisBlockCreator { +func createMockArgument(t *testing.T) ArgsGenesisBlockCreator { memDBMock := mock.NewMemDbMock() - storageManager := &mock.StorageManagerStub{DatabaseCalled: func() data.DBWriteCacher { - return memDBMock - }} + storageManager, _ := trie.NewTrieStorageManagerWithoutPruning(memDBMock) trieStorageManagers := make(map[string]data.StorageManager) trieStorageManagers[factory.UserAccountTrie] = storageManager @@ -34,7 +41,6 @@ func createMockArgument() ArgsGenesisBlockCreator { GenesisTime: 0, StartEpochNum: 0, PubkeyConv: mock.NewPubkeyConverterMock(32), - InitialNodesSetup: &mock.InitialNodesSetupHandlerStub{}, Blkc: &mock.BlockChainStub{}, Marshalizer: &mock.MarshalizerMock{}, Hasher: &mock.HasherMock{}, @@ -57,20 +63,14 @@ func createMockArgument() ArgsGenesisBlockCreator { SelfShardId: 0, } - arg.Accounts = &mock.AccountsStub{ - RootHashCalled: func() ([]byte, error) { - return make([]byte, 0), nil - }, - CommitCalled: func() ([]byte, error) { - return make([]byte, 0), nil - }, - SaveAccountCalled: func(account state.AccountHandler) error { - return nil - }, - LoadAccountCalled: func(address []byte) (state.AccountHandler, error) { - return state.NewEmptyUserAccount(), nil - }, - } + var err error + arg.Accounts, err = createAccountAdapter( + &mock.MarshalizerMock{}, + &mock.HasherMock{}, + factoryState.NewAccountCreator(), + trieStorageManagers[factory.UserAccountTrie], + ) + require.Nil(t, err) arg.ValidatorAccounts = &mock.AccountsStub{ RootHashCalled: func() ([]byte, error) { @@ -93,10 +93,11 @@ func createMockArgument() ArgsGenesisBlockCreator { ted := &economics.TestEconomicsData{ EconomicsData: &economics.EconomicsData{}, } - ted.SetGenesisNodePrice(big.NewInt(100)) + ted.SetGenesisNodePrice(nodePrice) ted.SetMinStep(big.NewInt(1)) - ted.SetTotalSupply(big.NewInt(10000)) + ted.SetTotalSupply(entireGenesisSupply) ted.SetUnJailPrice(big.NewInt(1)) + ted.SetMaxGasLimitPerBlock(math.MaxUint64) arg.Economics = ted.EconomicsData arg.Store = &mock.ChainStorerMock{ @@ -105,16 +106,46 @@ func createMockArgument() ArgsGenesisBlockCreator { }, } - arg.AccountsParser, _ = parsing.NewAccountsParser( + arg.AccountsParser, err = parsing.NewAccountsParser( "testdata/genesis.json", arg.Economics.TotalSupply(), arg.PubkeyConv, ) + require.Nil(t, err) - arg.SmartContractParser, _ = parsing.NewSmartContractsParser( + arg.SmartContractParser, err = parsing.NewSmartContractsParser( "testdata/smartcontracts.json", arg.PubkeyConv, ) + require.Nil(t, err) + + scAddressBytes, _ := hex.DecodeString("00000000000000000500761b8c4a25d3979359223208b412285f635e71300102") + stakedAddr, _ := hex.DecodeString("b00102030405060708090001020304050607080900010203040506070809000b") + arg.InitialNodesSetup = &mock.InitialNodesHandlerStub{ + InitialNodesInfoCalled: func() (map[uint32][]sharding.GenesisNodeInfoHandler, map[uint32][]sharding.GenesisNodeInfoHandler) { + return map[uint32][]sharding.GenesisNodeInfoHandler{ + 0: { + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: scAddressBytes, + PubKeyBytesValue: bytes.Repeat([]byte{1}, 128), + }, + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: stakedAddr, + PubKeyBytesValue: bytes.Repeat([]byte{2}, 128), + }, + }, + 1: { + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: scAddressBytes, + PubKeyBytesValue: bytes.Repeat([]byte{3}, 128), + }, + }, + }, make(map[uint32][]sharding.GenesisNodeInfoHandler) + }, + MinNumberOfNodesCalled: func() uint32 { + return 1 + }, + } return arg } @@ -122,7 +153,7 @@ func createMockArgument() ArgsGenesisBlockCreator { func TestGenesisBlockCreator_CreateGenesisBlocksShouldWork(t *testing.T) { t.Parallel() - arg := createMockArgument() + arg := createMockArgument(t) gbc, err := NewGenesisBlockCreator(arg) require.Nil(t, err) diff --git a/genesis/process/intermediate/delegationDeployProcessor.go b/genesis/process/intermediate/delegationDeployProcessor.go deleted file mode 100644 index 5eb143038d..0000000000 --- a/genesis/process/intermediate/delegationDeployProcessor.go +++ /dev/null @@ -1,85 +0,0 @@ -package intermediate - -import ( - "fmt" - "math/big" - "strings" - - "github.com/ElrondNetwork/elrond-go/core/check" - "github.com/ElrondNetwork/elrond-go/data/state" - "github.com/ElrondNetwork/elrond-go/genesis" -) - -const stakedPlaceholder = "%sc_total_stake%" - -var zero = big.NewInt(0) - -type delegationDeployProcessor struct { - genesis.DeployProcessor - accountsParser genesis.AccountsParser - pubkeyConv state.PubkeyConverter - nodePrice *big.Int -} - -// NewDelegationDeployProcessor returns a new deploy processor specialized for deploying delegation SC -func NewDelegationDeployProcessor( - deployProcessor genesis.DeployProcessor, - accountsParser genesis.AccountsParser, - pubkeyConv state.PubkeyConverter, - nodePrice *big.Int, -) (*delegationDeployProcessor, error) { - if check.IfNil(deployProcessor) { - return nil, genesis.ErrNilDeployProcessor - } - if check.IfNil(accountsParser) { - return nil, genesis.ErrNilAccountsParser - } - if check.IfNil(pubkeyConv) { - return nil, genesis.ErrNilPubkeyConverter - } - if nodePrice == nil { - return nil, genesis.ErrNilInitialNodePrice - } - if nodePrice.Cmp(zero) < 1 { - return nil, genesis.ErrInvalidInitialNodePrice - } - - ddp := &delegationDeployProcessor{ - DeployProcessor: deployProcessor, - accountsParser: accountsParser, - pubkeyConv: pubkeyConv, - nodePrice: nodePrice, - } - ddp.SetReplacePlaceholders(ddp.replaceDelegationPlaceholders) - - return ddp, nil -} - -func (ddp *delegationDeployProcessor) replaceDelegationPlaceholders( - txData string, - scResultingAddressBytes []byte, -) (string, error) { - - scResultingAddress := ddp.pubkeyConv.Encode(scResultingAddressBytes) - val := ddp.accountsParser.GetTotalStakedForDelegationAddress(scResultingAddress) - if val.Cmp(zero) < 1 { - return "", fmt.Errorf("%w, 0 or negative delegated value for resulting address %s", - genesis.ErrInvalidDelegationValue, scResultingAddress) - } - - exactDiv := big.NewInt(0).Set(val) - exactDiv.Mod(exactDiv, ddp.nodePrice) - if exactDiv.Cmp(zero) != 0 { - return "", fmt.Errorf("%w, not a node price multiple value, for resulting address %s", - genesis.ErrInvalidDelegationValue, scResultingAddress) - } - - txData = strings.Replace(txData, stakedPlaceholder, val.Text(16), -1) - - return txData, nil -} - -// IsInterfaceNil returns if underlying object is true -func (ddp *delegationDeployProcessor) IsInterfaceNil() bool { - return ddp == nil || ddp.DeployProcessor == nil -} diff --git a/genesis/process/intermediate/delegationDeployProcessor_test.go b/genesis/process/intermediate/delegationDeployProcessor_test.go deleted file mode 100644 index 4971ef0e67..0000000000 --- a/genesis/process/intermediate/delegationDeployProcessor_test.go +++ /dev/null @@ -1,158 +0,0 @@ -package intermediate - -import ( - "errors" - "math/big" - "testing" - - "github.com/ElrondNetwork/elrond-go/core/check" - "github.com/ElrondNetwork/elrond-go/genesis" - "github.com/ElrondNetwork/elrond-go/genesis/mock" - "github.com/stretchr/testify/assert" -) - -func TestNewDelegationDeployProcessor_NilDeployProcessorShouldErr(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - nil, - &mock.AccountsParserStub{}, - mock.NewPubkeyConverterMock(32), - big.NewInt(1), - ) - - assert.True(t, check.IfNil(ddp)) - assert.Equal(t, genesis.ErrNilDeployProcessor, err) -} - -func TestNewDelegationDeployProcessor_NilAccountsParserShouldErr(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - nil, - mock.NewPubkeyConverterMock(32), - big.NewInt(1), - ) - - assert.True(t, check.IfNil(ddp)) - assert.Equal(t, genesis.ErrNilAccountsParser, err) -} - -func TestNewDelegationDeployProcessor_NilPubkeyConverterShouldErr(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{}, - nil, - big.NewInt(1), - ) - - assert.True(t, check.IfNil(ddp)) - assert.Equal(t, genesis.ErrNilPubkeyConverter, err) -} - -func TestNewDelegationDeployProcessor_NilInitialNodePriceShouldErr(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{}, - mock.NewPubkeyConverterMock(32), - nil, - ) - - assert.True(t, check.IfNil(ddp)) - assert.Equal(t, genesis.ErrNilInitialNodePrice, err) -} - -func TestNewDelegationDeployProcessor_InvalidInitialNodePriceShouldErr(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{}, - mock.NewPubkeyConverterMock(32), - big.NewInt(0), - ) - - assert.True(t, check.IfNil(ddp)) - assert.Equal(t, genesis.ErrInvalidInitialNodePrice, err) -} - -func TestNewDelegationDeployProcessor_ShouldWork(t *testing.T) { - t.Parallel() - - ddp, err := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{}, - mock.NewPubkeyConverterMock(32), - big.NewInt(1), - ) - - assert.False(t, check.IfNil(ddp)) - assert.Nil(t, err) -} - -//------- replaceDelegationPlaceholders - -func TestDelegationDeployProcessor_ReplaceDelegationPlaceholdersNotStakedShouldErr(t *testing.T) { - t.Parallel() - - ddp, _ := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{ - GetTotalStakedForDelegationAddressCalled: func(delegationAddress string) *big.Int { - return big.NewInt(0) - }, - }, - mock.NewPubkeyConverterMock(32), - big.NewInt(1), - ) - - str, err := ddp.replaceDelegationPlaceholders("data", []byte("sc address")) - - assert.Equal(t, "", str) - assert.True(t, errors.Is(err, genesis.ErrInvalidDelegationValue)) -} - -func TestDelegationDeployProcessor_ReplaceDelegationPlaceholdersNotAnExactValueShouldErr(t *testing.T) { - t.Parallel() - - ddp, _ := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{ - GetTotalStakedForDelegationAddressCalled: func(delegationAddress string) *big.Int { - return big.NewInt(4) - }, - }, - mock.NewPubkeyConverterMock(32), - big.NewInt(3), - ) - - str, err := ddp.replaceDelegationPlaceholders("data", []byte("sc address")) - - assert.Equal(t, "", str) - assert.True(t, errors.Is(err, genesis.ErrInvalidDelegationValue)) -} - -func TestDelegationDeployProcessor_ReplaceDelegationPlaceholdersShouldWork(t *testing.T) { - t.Parallel() - - ddp, _ := NewDelegationDeployProcessor( - &mock.DeployProcessorStub{}, - &mock.AccountsParserStub{ - GetTotalStakedForDelegationAddressCalled: func(delegationAddress string) *big.Int { - return big.NewInt(6) - }, - }, - mock.NewPubkeyConverterMock(32), - big.NewInt(3), - ) - - str, err := ddp.replaceDelegationPlaceholders(stakedPlaceholder, []byte("sc address")) - - assert.Equal(t, "6", str) - assert.Nil(t, err) -} diff --git a/genesis/process/intermediate/delegationProcessor.go b/genesis/process/intermediate/delegationProcessor.go index ae643f8060..1c38978fd6 100644 --- a/genesis/process/intermediate/delegationProcessor.go +++ b/genesis/process/intermediate/delegationProcessor.go @@ -1,14 +1,36 @@ package intermediate import ( + "bytes" + "encoding/hex" "fmt" + "math/big" + "strings" + logger "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/genesis" + "github.com/ElrondNetwork/elrond-go/node/external" + "github.com/ElrondNetwork/elrond-go/process" "github.com/ElrondNetwork/elrond-go/sharding" ) -const stakeFunction = "stake" +// ArgDelegationProcessor is the argument used to construct a delegation processor +type ArgDelegationProcessor struct { + Executor genesis.TxExecutionProcessor + ShardCoordinator sharding.Coordinator + AccountsParser genesis.AccountsParser + SmartContractParser genesis.InitialSmartContractParser + NodesListSplitter genesis.NodesListSplitter + QueryService external.SCQueryService + NodePrice *big.Int +} + +const stakeFunction = "stakeGenesis" +const setBlsKeysFunction = "setBlsKeys" +const activateBlsKeysFunction = "activate" + +var log = logger.GetOrCreate("genesis/process/intermediate") type delegationProcessor struct { genesis.TxExecutionProcessor @@ -16,38 +38,45 @@ type delegationProcessor struct { accuntsParser genesis.AccountsParser smartContractsParser genesis.InitialSmartContractParser nodesListSplitter genesis.NodesListSplitter + queryService external.SCQueryService + nodePrice *big.Int } // NewDelegationProcessor returns a new delegation processor instance -func NewDelegationProcessor( - executor genesis.TxExecutionProcessor, - shardCoordinator sharding.Coordinator, - accountsParser genesis.AccountsParser, - smartContractParser genesis.InitialSmartContractParser, - nodesListSplitter genesis.NodesListSplitter, -) (*delegationProcessor, error) { - if check.IfNil(executor) { +func NewDelegationProcessor(arg ArgDelegationProcessor) (*delegationProcessor, error) { + if check.IfNil(arg.Executor) { return nil, genesis.ErrNilTxExecutionProcessor } - if check.IfNil(shardCoordinator) { + if check.IfNil(arg.ShardCoordinator) { return nil, genesis.ErrNilShardCoordinator } - if check.IfNil(accountsParser) { + if check.IfNil(arg.AccountsParser) { return nil, genesis.ErrNilAccountsParser } - if check.IfNil(smartContractParser) { + if check.IfNil(arg.SmartContractParser) { return nil, genesis.ErrNilSmartContractParser } - if check.IfNil(nodesListSplitter) { + if check.IfNil(arg.NodesListSplitter) { return nil, genesis.ErrNilNodesListSplitter } + if check.IfNil(arg.QueryService) { + return nil, genesis.ErrNilQueryService + } + if arg.NodePrice == nil { + return nil, genesis.ErrNilInitialNodePrice + } + if arg.NodePrice.Cmp(zero) <= 0 { + return nil, genesis.ErrInvalidInitialNodePrice + } return &delegationProcessor{ - TxExecutionProcessor: executor, - shardCoordinator: shardCoordinator, - accuntsParser: accountsParser, - smartContractsParser: smartContractParser, - nodesListSplitter: nodesListSplitter, + TxExecutionProcessor: arg.Executor, + shardCoordinator: arg.ShardCoordinator, + accuntsParser: arg.AccountsParser, + smartContractsParser: arg.SmartContractParser, + nodesListSplitter: arg.NodesListSplitter, + queryService: arg.QueryService, + nodePrice: arg.NodePrice, }, nil } @@ -57,18 +86,36 @@ func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, er if err != nil { return genesis.DelegationResult{}, err } - if len(smartContracts) == 0 { return genesis.DelegationResult{}, nil } + err = dp.setDelegationStartParameters(smartContracts) + if err != nil { + return genesis.DelegationResult{}, err + } + + _, err = dp.executeManageBlsKeys(smartContracts, dp.setBlsKey, setBlsKeysFunction) + if err != nil { + return genesis.DelegationResult{}, err + } + dr := genesis.DelegationResult{} dr.NumTotalStaked, err = dp.executeStake(smartContracts) if err != nil { return genesis.DelegationResult{}, err } - dr.NumTotalDelegated, err = dp.activateBlsKeys(smartContracts) + dr.NumTotalDelegated, err = dp.executeManageBlsKeys(smartContracts, dp.activate, activateBlsKeysFunction) + if err != nil { + return genesis.DelegationResult{}, err + } + + err = dp.executeVerify(smartContracts) + if err != nil { + return genesis.DelegationResult{}, err + } + return dr, err } @@ -86,20 +133,103 @@ func (dp *delegationProcessor) getDelegationScOnCurrentShard() ([]genesis.Initia } } + log.Trace("getDelegationScOnCurrentShard", + "num delegation SC", len(smartContracts), + "shard ID", dp.shardCoordinator.SelfId(), + ) return smartContracts, nil } +func (dp *delegationProcessor) setDelegationStartParameters(smartContracts []genesis.InitialSmartContractHandler) error { + for _, sc := range smartContracts { + delegatedNodes := dp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) + numNodes := len(delegatedNodes) + + log.Trace("setDelegationStartParameters", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + "num delegated nodes", numNodes, + "node price", dp.nodePrice.String(), + "shard ID", dp.shardCoordinator.SelfId(), + ) + + err := dp.executeSetNumNodes(numNodes, sc) + if err != nil { + return err + } + + err = dp.executeSetNodePrice(sc) + if err != nil { + return err + } + } + + return nil +} + +func (dp *delegationProcessor) executeSetNumNodes(numNodes int, sc genesis.InitialSmartContractHandler) error { + setNumNodesTxData := fmt.Sprintf("setNrNodes@%x", numNodes) + + nonce, err := dp.GetNonce(sc.OwnerBytes()) + if err != nil { + return err + } + + return dp.ExecuteTransaction( + nonce, + sc.OwnerBytes(), + sc.AddressBytes(), + zero, + []byte(setNumNodesTxData), + ) +} + +func (dp *delegationProcessor) executeSetNodePrice(sc genesis.InitialSmartContractHandler) error { + setStakePerNodeTxData := fmt.Sprintf("setStakePerNode@%x", dp.nodePrice) + + nonce, err := dp.GetNonce(sc.OwnerBytes()) + if err != nil { + return err + } + + return dp.ExecuteTransaction( + nonce, + sc.OwnerBytes(), + sc.AddressBytes(), + zero, + []byte(setStakePerNodeTxData), + ) +} + func (dp *delegationProcessor) executeStake(smartContracts []genesis.InitialSmartContractHandler) (int, error) { stakedOnDelegation := 0 for _, sc := range smartContracts { accounts := dp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) + if len(accounts) == 0 { + log.Debug("genesis delegation SC was not delegated by any account", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + ) + continue + } + + totalDelegated := big.NewInt(0) for _, ac := range accounts { err := dp.stake(ac, sc) if err != nil { return 0, fmt.Errorf("%w while calling stake function from account %s", err, ac.GetAddress()) } + + totalDelegated.Add(totalDelegated, ac.GetDelegationHandler().GetValue()) } + + log.Trace("executeStake", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + "num accounts", len(accounts), + "total delegated", totalDelegated, + ) stakedOnDelegation += len(accounts) } @@ -113,36 +243,27 @@ func (dp *delegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesi if check.IfNil(dh) { return genesis.ErrNilDelegationHandler } + if dh.GetValue() == nil { + return genesis.ErrInvalidDelegationValue + } var err error + var nonce = uint64(0) if isIntraShardCall { - //intra shard transaction, get current nonce, add to balance the delegation value - // in order to make the tx processor work - nonce, errGetNonce := dp.GetNonce(ac.AddressBytes()) - if errGetNonce != nil { - return errGetNonce - } - - err = dp.AddBalance(ac.AddressBytes(), dh.GetValue()) + //intra shard transaction, get current nonce in order to make the tx processor work + nonce, err = dp.GetNonce(ac.AddressBytes()) if err != nil { return err } - - return dp.ExecuteTransaction( - nonce, - ac.AddressBytes(), - sc.AddressBytes(), - dh.GetValue(), - []byte(stakeFunction), - ) } + stakeData := fmt.Sprintf("%s@%s", stakeFunction, dh.GetValue().Text(16)) err = dp.ExecuteTransaction( - 0, + nonce, ac.AddressBytes(), sc.AddressBytes(), - dh.GetValue(), - []byte(stakeFunction), + zero, + []byte(stakeData), ) if err != nil { return err @@ -151,8 +272,17 @@ func (dp *delegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesi return nil } -func (dp *delegationProcessor) activateBlsKeys(smartContracts []genesis.InitialSmartContractHandler) (int, error) { - //mockSignature := "genesis" +func (dp *delegationProcessor) executeManageBlsKeys( + smartContracts []genesis.InitialSmartContractHandler, + handler func(node sharding.GenesisNodeInfoHandler) string, + function string, +) (int, error) { + + log.Trace("executeManageSetBlsKeys", + "num delegation SC", len(smartContracts), + "shard ID", dp.shardCoordinator.SelfId(), + "function", function, + ) totalDelegated := 0 for _, sc := range smartContracts { @@ -160,54 +290,166 @@ func (dp *delegationProcessor) activateBlsKeys(smartContracts []genesis.InitialS lenDelegated := len(delegatedNodes) if lenDelegated == 0 { + log.Debug("genesis delegation SC does not have staked nodes", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + "function", function, + ) continue } totalDelegated += lenDelegated - //TODO refactor this: use the new delegation contract version that will only activate the nodes internally - //setBlsKeys := make([]string, 0, lenDelegated) - //activateKeys := make([]string, 0, lenDelegated) - //for _, node := range delegatedNodes { - // setBlsKeys = append(setBlsKeys, hex.EncodeToString(node.PubKeyBytes())) - // activateKeys = append(activateKeys, mockSignature) - //} - // - //nonce, err := dp.GetNonce(sc.OwnerBytes()) - //if err != nil { - // return 0, err - //} - // - //setString := fmt.Sprintf("setBlsKeys@%d@%s", lenDelegated, strings.Join(setBlsKeys, "@")) - //err = dp.ExecuteTransaction( - // nonce, - // sc.OwnerBytes(), - // sc.AddressBytes(), - // big.NewInt(0), - // []byte(setString), - //) - //if err != nil { - // return 0, err - //} - // - //nonce++ - // - //hexLenDelegated := hex.EncodeToString(big.NewInt(int64(lenDelegated)).Bytes()) - //activateString := fmt.Sprintf("activate@%s@%s", hexLenDelegated, strings.Join(activateKeys, "@")) - //err = dp.ExecuteTransaction( - // nonce, - // sc.OwnerBytes(), - // sc.AddressBytes(), - // big.NewInt(0), - // []byte(activateString), - //) - //if err != nil { - // return 0, err - //} + log.Trace("executeSetBlsKeys", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + "num nodes", lenDelegated, + "shard ID", dp.shardCoordinator.SelfId(), + "function", function, + ) + + arguments := make([]string, 0, len(delegatedNodes)+1) + arguments = append(arguments, function) + for _, node := range delegatedNodes { + arg := handler(node) + arguments = append(arguments, arg) + } + + nonce, err := dp.GetNonce(sc.OwnerBytes()) + if err != nil { + return 0, err + } + + err = dp.ExecuteTransaction( + nonce, + sc.OwnerBytes(), + sc.AddressBytes(), + big.NewInt(0), + []byte(strings.Join(arguments, "@")), + ) + if err != nil { + return 0, err + } } return totalDelegated, nil } +func (dp *delegationProcessor) setBlsKey(node sharding.GenesisNodeInfoHandler) string { + return hex.EncodeToString(node.PubKeyBytes()) +} + +func (dp *delegationProcessor) activate(_ sharding.GenesisNodeInfoHandler) string { + mockSignature := []byte("genesis signature") + + return hex.EncodeToString(mockSignature) +} + +func (dp *delegationProcessor) executeVerify(smartContracts []genesis.InitialSmartContractHandler) error { + for _, sc := range smartContracts { + err := dp.verify(sc) + if err != nil { + return fmt.Errorf("%w for contract %s, owner %s", err, sc.Address(), sc.GetOwner()) + } + } + + return nil +} + +func (dp *delegationProcessor) verify(sc genesis.InitialSmartContractHandler) error { + err := dp.verifyStakedValue(sc) + if err != nil { + return fmt.Errorf("%w for verifyStakedValue", err) + } + + err = dp.verifyRegisteredNodes(sc) + if err != nil { + return fmt.Errorf("%w for verifyRegisteredNodes", err) + } + + return nil +} + +func (dp *delegationProcessor) verifyStakedValue(sc genesis.InitialSmartContractHandler) error { + scQueryStakeValue := &process.SCQuery{ + ScAddress: sc.AddressBytes(), + FuncName: "getFilledStake", + Arguments: [][]byte{}, + } + vmOutputStakeValue, err := dp.queryService.ExecuteQuery(scQueryStakeValue) + if err != nil { + return err + } + if len(vmOutputStakeValue.ReturnData) != 1 { + return fmt.Errorf("%w return data should have contained one element", genesis.ErrWhileVerifyingDelegation) + } + scStakedValue := big.NewInt(0).SetBytes(vmOutputStakeValue.ReturnData[0]) + providedStakedValue := big.NewInt(0) + providedDelegators := dp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) + + for _, delegator := range providedDelegators { + if check.IfNil(delegator) { + continue + } + dh := delegator.GetDelegationHandler() + if check.IfNil(dh) { + continue + } + if dh.GetValue() == nil { + continue + } + providedStakedValue.Add(providedStakedValue, dh.GetValue()) + } + if scStakedValue.Cmp(providedStakedValue) != 0 { + return fmt.Errorf("%w staked data mismatch: from SC: %s, provided: %s", + genesis.ErrWhileVerifyingDelegation, scStakedValue.String(), providedStakedValue.String()) + } + + return nil +} + +func (dp *delegationProcessor) verifyRegisteredNodes(sc genesis.InitialSmartContractHandler) error { + scQueryBlsKeys := &process.SCQuery{ + ScAddress: sc.AddressBytes(), + FuncName: "getBlsKeys", + Arguments: [][]byte{}, + } + + vmOutputBlsKeys, err := dp.queryService.ExecuteQuery(scQueryBlsKeys) + if err != nil { + return err + } + delegatedNodes := dp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) + nodesAddresses := make([][]byte, 0, len(delegatedNodes)) + for _, node := range delegatedNodes { + nodesAddresses = append(nodesAddresses, node.PubKeyBytes()) + } + + if len(vmOutputBlsKeys.ReturnData) != len(nodesAddresses) { + return fmt.Errorf("%w staked nodes mismatch: %d found in SC, %d provided", + genesis.ErrWhileVerifyingDelegation, len(vmOutputBlsKeys.ReturnData), len(nodesAddresses)) + } + + return dp.sameElements(vmOutputBlsKeys.ReturnData, nodesAddresses) +} + +func (dp *delegationProcessor) sameElements(slice1 [][]byte, slice2 [][]byte) error { + for _, elem1 := range slice1 { + found := false + for _, elem2 := range slice2 { + if bytes.Equal(elem1, elem2) { + found = true + break + } + } + + if !found { + return fmt.Errorf("%w for key %s", genesis.ErrMissingElement, hex.EncodeToString(elem1)) + } + } + + return nil +} + // IsInterfaceNil returns if underlying object is true func (dp *delegationProcessor) IsInterfaceNil() bool { return dp == nil || dp.TxExecutionProcessor == nil diff --git a/genesis/process/intermediate/delegationProcessor_test.go b/genesis/process/intermediate/delegationProcessor_test.go index 7b7b207f29..8950bd214f 100644 --- a/genesis/process/intermediate/delegationProcessor_test.go +++ b/genesis/process/intermediate/delegationProcessor_test.go @@ -11,20 +11,30 @@ import ( "github.com/ElrondNetwork/elrond-go/genesis" "github.com/ElrondNetwork/elrond-go/genesis/data" "github.com/ElrondNetwork/elrond-go/genesis/mock" + "github.com/ElrondNetwork/elrond-go/process" "github.com/ElrondNetwork/elrond-go/sharding" + vmcommon "github.com/ElrondNetwork/elrond-vm-common" "github.com/stretchr/testify/assert" ) +func createMockArg() ArgDelegationProcessor { + return ArgDelegationProcessor{ + Executor: &mock.TxExecutionProcessorStub{}, + ShardCoordinator: &mock.ShardCoordinatorMock{}, + AccountsParser: &mock.AccountsParserStub{}, + SmartContractParser: &mock.SmartContractParserStub{}, + NodesListSplitter: &mock.NodesListSplitterStub{}, + QueryService: &mock.QueryServiceStub{}, + NodePrice: big.NewInt(10), + } +} + func TestNewDelegationProcessor_NilExecutorShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - nil, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{}, - &mock.NodesListSplitterStub{}, - ) + arg := createMockArg() + arg.Executor = nil + dp, err := NewDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilTxExecutionProcessor, err) @@ -33,13 +43,9 @@ func TestNewDelegationProcessor_NilExecutorShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{}, - nil, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{}, - &mock.NodesListSplitterStub{}, - ) + arg := createMockArg() + arg.ShardCoordinator = nil + dp, err := NewDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilShardCoordinator, err) @@ -48,13 +54,9 @@ func TestNewDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{}, - &mock.ShardCoordinatorMock{}, - nil, - &mock.SmartContractParserStub{}, - &mock.NodesListSplitterStub{}, - ) + arg := createMockArg() + arg.AccountsParser = nil + dp, err := NewDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilAccountsParser, err) @@ -63,13 +65,9 @@ func TestNewDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{}, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - nil, - &mock.NodesListSplitterStub{}, - ) + arg := createMockArg() + arg.SmartContractParser = nil + dp, err := NewDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilSmartContractParser, err) @@ -78,28 +76,52 @@ func TestNewDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilNodesSplitterShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{}, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{}, - nil, - ) + arg := createMockArg() + arg.NodesListSplitter = nil + dp, err := NewDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilNodesListSplitter, err) } +func TestNewDelegationProcessor_NilQueryServiceShouldErr(t *testing.T) { + t.Parallel() + + arg := createMockArg() + arg.QueryService = nil + dp, err := NewDelegationProcessor(arg) + + assert.True(t, check.IfNil(dp)) + assert.Equal(t, genesis.ErrNilQueryService, err) +} + +func TestNewDelegationProcessor_NilNodePriceShouldErr(t *testing.T) { + t.Parallel() + + arg := createMockArg() + arg.NodePrice = nil + dp, err := NewDelegationProcessor(arg) + + assert.True(t, check.IfNil(dp)) + assert.Equal(t, genesis.ErrNilInitialNodePrice, err) +} + +func TestNewDelegationProcessor_ZeroNodePriceShouldErr(t *testing.T) { + t.Parallel() + + arg := createMockArg() + arg.NodePrice = big.NewInt(0) + dp, err := NewDelegationProcessor(arg) + + assert.True(t, check.IfNil(dp)) + assert.Equal(t, genesis.ErrInvalidInitialNodePrice, err) +} + func TestNewDelegationProcessor_ShouldWork(t *testing.T) { t.Parallel() - dp, err := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{}, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{}, - &mock.NodesListSplitterStub{}, - ) + arg := createMockArg() + dp, err := NewDelegationProcessor(arg) assert.False(t, check.IfNil(dp)) assert.Nil(t, err) @@ -111,23 +133,21 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) t.Parallel() expectedErr := fmt.Errorf("expected error") - dp, _ := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{ - ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { - assert.Fail(t, "should have not execute a transaction") + arg := createMockArg() + arg.Executor = &mock.TxExecutionProcessorStub{ + ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { + assert.Fail(t, "should have not execute a transaction") - return nil - }, + return nil }, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{ - InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { - return nil, expectedErr - }, + } + arg.SmartContractParser = &mock.SmartContractParserStub{ + InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { + return nil, expectedErr }, - &mock.NodesListSplitterStub{}, - ) + } + + dp, _ := NewDelegationProcessor(arg) result, err := dp.ExecuteDelegation() @@ -138,29 +158,26 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) func TestDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *testing.T) { t.Parallel() - dp, _ := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{ - ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { - assert.Fail(t, "should have not execute a transaction") + arg := createMockArg() + arg.Executor = &mock.TxExecutionProcessorStub{ + ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { + assert.Fail(t, "should have not execute a transaction") - return nil - }, + return nil }, - &mock.ShardCoordinatorMock{}, - &mock.AccountsParserStub{}, - &mock.SmartContractParserStub{ - InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { - return map[uint32][]genesis.InitialSmartContractHandler{ - 0: { - &data.InitialSmartContract{ - Type: "test", - }, + } + arg.SmartContractParser = &mock.SmartContractParserStub{ + InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { + return map[uint32][]genesis.InitialSmartContractHandler{ + 0: { + &data.InitialSmartContract{ + Type: "test", }, - }, nil - }, + }, + }, nil }, - &mock.NodesListSplitterStub{}, - ) + } + dp, _ := NewDelegationProcessor(arg) result, err := dp.ExecuteDelegation() @@ -174,61 +191,103 @@ func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { staker1 := []byte("stakerB") staker2 := []byte("stakerC") delegationSc := []byte("delegation SC") + pubkey1 := []byte("pubkey1") + pubkey2 := []byte("pubkey2") + pubkey3 := []byte("pubkey3") + + arg := createMockArg() + arg.Executor = &mock.TxExecutionProcessorStub{ + ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { + isStakeCall := strings.Contains(string(data), "stake") + isStaker := bytes.Equal(sndAddr, staker1) || bytes.Equal(sndAddr, staker2) + if isStakeCall && !isStaker { + assert.Fail(t, "stake should have been called by the one of the stakers") + } + + return nil + }, + } + arg.ShardCoordinator = &mock.ShardCoordinatorMock{ + SelfShardId: 0, + NumOfShards: 2, + } + arg.AccountsParser = &mock.AccountsParserStub{ + GetInitialAccountsForDelegatedCalled: func(addressBytes []byte) []genesis.InitialAccountHandler { + if bytes.Equal(addressBytes, delegationSc) { + ia1 := &data.InitialAccount{ + Delegation: &data.DelegationData{ + Value: big.NewInt(2), + }, + } + ia1.SetAddressBytes(staker1) + ia1.Delegation.SetAddressBytes(delegationSc) - dp, _ := NewDelegationProcessor( - &mock.TxExecutionProcessorStub{ - ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { - isStakeCall := strings.Contains(string(data), "stake") - isStaker := bytes.Equal(sndAddr, staker1) || bytes.Equal(sndAddr, staker2) - if isStakeCall && !isStaker { - assert.Fail(t, "stake should have been called by the one of the stakers") + ia2 := &data.InitialAccount{ + Delegation: &data.DelegationData{ + Value: big.NewInt(2), + }, } + ia2.SetAddressBytes(staker2) + ia2.Delegation.SetAddressBytes(delegationSc) - return nil - }, + return []genesis.InitialAccountHandler{ia1, ia2} + } + + return make([]genesis.InitialAccountHandler, 0) }, - &mock.ShardCoordinatorMock{ - SelfShardId: 0, - NumOfShards: 2, + } + arg.SmartContractParser = &mock.SmartContractParserStub{ + InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { + sc := &data.InitialSmartContract{ + Type: genesis.DelegationType, + } + sc.SetAddressBytes(delegationSc) + + return map[uint32][]genesis.InitialSmartContractHandler{ + 0: {sc}, + }, nil }, - &mock.AccountsParserStub{ - GetInitialAccountsForDelegatedCalled: func(addressBytes []byte) []genesis.InitialAccountHandler { - if bytes.Equal(addressBytes, delegationSc) { - ia1 := &data.InitialAccount{ - Delegation: &data.DelegationData{}, - } - ia1.SetAddressBytes(staker1) - - ia2 := &data.InitialAccount{ - Delegation: &data.DelegationData{}, - } - ia2.SetAddressBytes(staker2) - - return []genesis.InitialAccountHandler{ia1, ia2} - } + } + arg.QueryService = &mock.QueryServiceStub{ + ExecuteQueryCalled: func(query *process.SCQuery) (*vmcommon.VMOutput, error) { + if query.FuncName == "getFilledStake" { + return &vmcommon.VMOutput{ + ReturnData: [][]byte{big.NewInt(4).Bytes()}, + }, nil + } + if query.FuncName == "getBlsKeys" { + return &vmcommon.VMOutput{ + ReturnData: [][]byte{pubkey2, pubkey3, pubkey1}, //random order should work + }, nil + } - return make([]genesis.InitialAccountHandler, 0) - }, + return nil, fmt.Errorf("unexpected function") }, - &mock.SmartContractParserStub{ - InitialSmartContractsSplitOnOwnersShardsCalled: func(shardCoordinator sharding.Coordinator) (map[uint32][]genesis.InitialSmartContractHandler, error) { - sc := &data.InitialSmartContract{ - Type: genesis.DelegationType, - } - sc.SetAddressBytes(delegationSc) - - return map[uint32][]genesis.InitialSmartContractHandler{ - 0: {sc}, - }, nil - }, + } + arg.NodesListSplitter = &mock.NodesListSplitterStub{ + GetDelegatedNodesCalled: func(delegationScAddress []byte) []sharding.GenesisNodeInfoHandler { + return []sharding.GenesisNodeInfoHandler{ + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: delegationSc, + PubKeyBytesValue: pubkey1, + }, + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: delegationSc, + PubKeyBytesValue: pubkey2, + }, + &mock.GenesisNodeInfoHandlerMock{ + AddressBytesValue: delegationSc, + PubKeyBytesValue: pubkey3, + }, + } }, - &mock.NodesListSplitterStub{}, - ) + } + dp, _ := NewDelegationProcessor(arg) result, err := dp.ExecuteDelegation() expectedResult := genesis.DelegationResult{ - NumTotalDelegated: 0, + NumTotalDelegated: 3, NumTotalStaked: 2, } diff --git a/genesis/process/intermediate/deployProcessor.go b/genesis/process/intermediate/deployProcessor.go index ab1106297e..084c063e09 100644 --- a/genesis/process/intermediate/deployProcessor.go +++ b/genesis/process/intermediate/deployProcessor.go @@ -2,11 +2,11 @@ package intermediate import ( "encoding/hex" + "fmt" "io/ioutil" "math/big" "path/filepath" "strings" - "sync" "github.com/ElrondNetwork/elrond-go/core/check" "github.com/ElrondNetwork/elrond-go/data/state" @@ -21,12 +21,10 @@ const auctionScAddressPlaceholder = "%auction_sc_address%" type deployProcessor struct { genesis.TxExecutionProcessor - pubkeyConv state.PubkeyConverter - mutReplacePlaceholders sync.RWMutex - replacePlaceholders func(txData string, scResultingAddressBytes []byte) (string, error) - getScCodeAsHex func(filename string) (string, error) - blockchainHook process.BlockChainHookHandler - emptyAddress []byte + pubkeyConv state.PubkeyConverter + getScCodeAsHex func(filename string) (string, error) + blockchainHook process.BlockChainHookHandler + emptyAddress []byte } // NewDeployProcessor returns a new instance of deploy processor able to deploy SC @@ -78,27 +76,56 @@ func (dp *deployProcessor) Deploy(sc genesis.InitialSmartContractHandler) error } sc.SetAddressBytes(scResultingAddressBytes) + sc.SetAddress(dp.pubkeyConv.Encode(scResultingAddressBytes)) vmType := sc.GetVmType() - deployTxData := strings.Join([]string{code, vmType, codeMetadataHexForInitialSC}, "@") - deployTxData = dp.applyCommonPlaceholders(deployTxData) - - dp.mutReplacePlaceholders.RLock() - if dp.replacePlaceholders != nil { - deployTxData, err = dp.replacePlaceholders(deployTxData, scResultingAddressBytes) - if err != nil { - return err - } + initParams := dp.applyCommonPlaceholders(sc.GetInitParameters()) + arguments := []string{code, vmType, codeMetadataHexForInitialSC} + if len(initParams) > 0 { + arguments = append(arguments, initParams) + } + deployTxData := strings.Join(arguments, "@") + + log.Trace("deploying genesis SC", + "SC owner", sc.GetOwner(), + "SC address", sc.Address(), + "type", sc.GetType(), + "VM type", sc.GetVmType(), + "init params", initParams, + ) + + accountExists := dp.AccountExists(scResultingAddressBytes) + if accountExists { + return fmt.Errorf("%w for SC address %s, owner %s with nonce %d", + genesis.ErrAccountAlreadyExists, + sc.Address(), + sc.GetOwner(), + nonce, + ) } - dp.mutReplacePlaceholders.RUnlock() - return dp.ExecuteTransaction( + err = dp.ExecuteTransaction( nonce, sc.OwnerBytes(), dp.emptyAddress, big.NewInt(0), []byte(deployTxData), ) + if err != nil { + return err + } + + accountExists = dp.AccountExists(scResultingAddressBytes) + if !accountExists { + return fmt.Errorf("%w for SC address %s, owner %s with nonce %d", + genesis.ErrAccountNotCreated, + sc.Address(), + sc.GetOwner(), + nonce, + ) + } + + return nil } func (dp *deployProcessor) applyCommonPlaceholders(txData string) string { @@ -117,13 +144,6 @@ func (dp *deployProcessor) getSCCodeAsHex(filename string) (string, error) { return hex.EncodeToString(code), nil } -// SetReplacePlaceholders sets the replace placeholder custom handler -func (dp *deployProcessor) SetReplacePlaceholders(handler func(txData string, scResultingAddressBytes []byte) (string, error)) { - dp.mutReplacePlaceholders.Lock() - dp.replacePlaceholders = handler - dp.mutReplacePlaceholders.Unlock() -} - // IsInterfaceNil returns if underlying object is true func (dp *deployProcessor) IsInterfaceNil() bool { return dp == nil || dp.TxExecutionProcessor == nil diff --git a/genesis/process/intermediate/deployProcessor_test.go b/genesis/process/intermediate/deployProcessor_test.go index 7d7880b1b2..eab34ae3fc 100644 --- a/genesis/process/intermediate/deployProcessor_test.go +++ b/genesis/process/intermediate/deployProcessor_test.go @@ -131,29 +131,6 @@ func TestDeployProcessor_DeployNewAddressFailsShouldErr(t *testing.T) { assert.Equal(t, expectedErr, err) } -func TestDeployProcessor_DeployReplacePlaceholdersFailsShouldErr(t *testing.T) { - t.Parallel() - - expectedErr := fmt.Errorf("expected error") - dp, _ := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - mock.NewPubkeyConverterMock(0), - &mock.BlockChainHookHandlerMock{}, - ) - dp.getScCodeAsHex = func(filename string) (string, error) { - return "", nil - } - dp.SetReplacePlaceholders( - func(txData string, scResultingAddressBytes []byte) (string, error) { - return "", expectedErr - }, - ) - - err := dp.Deploy(&data.InitialSmartContract{}) - - assert.Equal(t, expectedErr, err) -} - func TestDeployProcessor_DeployShouldWork(t *testing.T) { t.Parallel() @@ -163,6 +140,7 @@ func TestDeployProcessor_DeployShouldWork(t *testing.T) { executeCalled := false testCode := "code" vmType := "0500" + accountExists := false dp, _ := NewDeployProcessor( &mock.TxExecutionProcessorStub{ GetNonceCalled: func(senderBytes []byte) (uint64, error) { @@ -194,6 +172,12 @@ func TestDeployProcessor_DeployShouldWork(t *testing.T) { executeCalled = true return nil }, + AccountExistsCalled: func(address []byte) bool { + result := accountExists + accountExists = true + + return result + }, }, mock.NewPubkeyConverterMock(lenAddress), &mock.BlockChainHookHandlerMock{ diff --git a/genesis/process/intermediate/txExecutionProcessor.go b/genesis/process/intermediate/txExecutionProcessor.go index f6f86236d3..55e5c6ca40 100644 --- a/genesis/process/intermediate/txExecutionProcessor.go +++ b/genesis/process/intermediate/txExecutionProcessor.go @@ -66,6 +66,13 @@ func (tep *txExecutionProcessor) GetNonce(senderBytes []byte) (uint64, error) { return accnt.GetNonce(), nil } +// AccountExists returns if an account exists in the accounts DB +func (tep *txExecutionProcessor) AccountExists(address []byte) bool { + _, err := tep.accounts.GetExistingAccount(address) + + return err == nil +} + // AddBalance adds the provided value on the balance field func (tep *txExecutionProcessor) AddBalance(senderBytes []byte, value *big.Int) error { accnt, err := tep.accounts.LoadAccount(senderBytes) diff --git a/genesis/process/intermediate/variables.go b/genesis/process/intermediate/variables.go new file mode 100644 index 0000000000..b2807fba52 --- /dev/null +++ b/genesis/process/intermediate/variables.go @@ -0,0 +1,5 @@ +package intermediate + +import "math/big" + +var zero = big.NewInt(0) diff --git a/genesis/process/metaGenesisBlockCreator.go b/genesis/process/metaGenesisBlockCreator.go index 20abbc902e..86ed3ad78d 100644 --- a/genesis/process/metaGenesisBlockCreator.go +++ b/genesis/process/metaGenesisBlockCreator.go @@ -48,11 +48,6 @@ func CreateMetaGenesisBlock(arg ArgsGenesisBlockCreator, nodesListSplitter genes return nil, err } - _, err = arg.Accounts.Commit() - if err != nil { - return nil, err - } - err = setStakedData(arg, processors.txProcessor, nodesListSplitter) if err != nil { return nil, err @@ -333,6 +328,11 @@ func createProcessorsForMetaGenesisBlock(arg ArgsGenesisBlockCreator) (*genesisP return nil, err } + queryService, err := smartContract.NewSCQueryService(vmContainer, arg.Economics) + if err != nil { + return nil, err + } + return &genesisProcessors{ txCoordinator: txCoordinator, systemSCs: virtualMachineFactory.SystemSmartContractContainer(), @@ -341,6 +341,7 @@ func createProcessorsForMetaGenesisBlock(arg ArgsGenesisBlockCreator) (*genesisP scProcessor: scProcessor, scrProcessor: scProcessor, rwdProcessor: nil, + queryService: queryService, }, nil } @@ -380,11 +381,6 @@ func deploySystemSmartContracts( } } - _, err := arg.Accounts.Commit() - if err != nil { - return err - } - return nil } diff --git a/genesis/process/shardGenesisBlockCreator.go b/genesis/process/shardGenesisBlockCreator.go index ffd845d155..a9cba7c987 100644 --- a/genesis/process/shardGenesisBlockCreator.go +++ b/genesis/process/shardGenesisBlockCreator.go @@ -393,6 +393,11 @@ func createProcessorsForShard(arg ArgsGenesisBlockCreator) (*genesisProcessors, return nil, err } + queryService, err := smartContract.NewSCQueryService(vmContainer, arg.Economics) + if err != nil { + return nil, err + } + return &genesisProcessors{ txCoordinator: txCoordinator, systemSCs: nil, @@ -401,6 +406,7 @@ func createProcessorsForShard(arg ArgsGenesisBlockCreator) (*genesisProcessors, scrProcessor: scProcessor, rwdProcessor: rewardsTxProcessor, blockchainHook: vmFactoryImpl.BlockChainHookImpl(), + queryService: queryService, }, nil } @@ -450,16 +456,6 @@ func deployInitialSmartContract( switch sc.GetType() { case genesis.DelegationType: - deployProc, err = intermediate.NewDelegationDeployProcessor( - deployProc, - arg.AccountsParser, - arg.PubkeyConv, - arg.Economics.GenesisNodePrice(), - ) - if err != nil { - return err - } - deployMetrics.numDelegation++ default: deployMetrics.numOtherTypes++ @@ -509,13 +505,17 @@ func executeDelegation( return genesis.DelegationResult{}, err } - delegationProcessor, err := intermediate.NewDelegationProcessor( - txExecutor, - arg.ShardCoordinator, - arg.AccountsParser, - arg.SmartContractParser, - nodesListSplitter, - ) + argDP := intermediate.ArgDelegationProcessor{ + Executor: txExecutor, + ShardCoordinator: arg.ShardCoordinator, + AccountsParser: arg.AccountsParser, + SmartContractParser: arg.SmartContractParser, + NodesListSplitter: nodesListSplitter, + QueryService: processors.queryService, + NodePrice: arg.Economics.GenesisNodePrice(), + } + + delegationProcessor, err := intermediate.NewDelegationProcessor(argDP) if err != nil { return genesis.DelegationResult{}, err } diff --git a/genesis/process/testdata/delegation.wasm b/genesis/process/testdata/delegation.wasm new file mode 100755 index 0000000000000000000000000000000000000000..51a41a0896eca8f95a086c1198c6d373750d15fd GIT binary patch literal 52245 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 HV+{O1ysfPT literal 0 HcmV?d00001 diff --git a/genesis/process/testdata/genesis.json b/genesis/process/testdata/genesis.json index 106c768c21..a535a79f80 100644 --- a/genesis/process/testdata/genesis.json +++ b/genesis/process/testdata/genesis.json @@ -1,6 +1,6 @@ [ { - "address": "0001", + "address": "a00102030405060708090001020304050607080900010203040506070809000a", "supply": "5000", "balance": "5000", "stakingvalue": "0", @@ -10,13 +10,23 @@ } }, { - "address": "0002", - "supply": "5000", + "address": "b00102030405060708090001020304050607080900010203040506070809000b", + "supply": "7000", "balance": "2000", - "stakingvalue": "3000", + "stakingvalue": "5000", "delegation": { "address": "", "value": "0" } + }, + { + "address": "c00102030405060708090001020304050607080900010203040506070809000c", + "supply": "10000", + "balance": "0", + "stakingvalue": "0", + "delegation": { + "address": "00000000000000000500761b8c4a25d3979359223208b412285f635e71300102", + "value": "10000" + } } ] diff --git a/genesis/process/testdata/smartcontracts.json b/genesis/process/testdata/smartcontracts.json index 5672251414..d2b34368fc 100644 --- a/genesis/process/testdata/smartcontracts.json +++ b/genesis/process/testdata/smartcontracts.json @@ -2,6 +2,15 @@ { "owner": "0102030405060708090001020304050607080900010203040506070809000102", "filename": "testdata/answer.wasm", - "vm-type": "0501" + "vm-type": "0500", + "init-parameters": "", + "type": "test" + }, + { + "owner": "0102030405060708090001020304050607080900010203040506070809000102", + "filename": "testdata/delegation.wasm", + "vm-type": "0500", + "init-parameters": "0BB8@%auction_sc_address%@0A61D0", + "type": "delegation" } ] From d22f7790a403d9ae0b60ea8db34ea816ee35c396 Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 15:36:48 +0300 Subject: [PATCH 65/79] try catch the bug --- ...chChangeWithNodesShufflingAndRater_test.go | 1 - integrationTests/testInitializer.go | 36 ++++ integrationTests/testProcessorNode.go | 7 +- .../testProcessorNodeWithMultisigner.go | 164 ++++++++++++++++++ .../vm/systemVM/stakingSC_test.go | 144 ++++++++++----- vm/systemSmartContracts/auction.go | 14 +- vm/systemSmartContracts/staking.go | 3 +- 7 files changed, 317 insertions(+), 52 deletions(-) diff --git a/integrationTests/multiShard/endOfEpoch/epochChangeWithNodesShufflingAndRater/epochChangeWithNodesShufflingAndRater_test.go b/integrationTests/multiShard/endOfEpoch/epochChangeWithNodesShufflingAndRater/epochChangeWithNodesShufflingAndRater_test.go index ee154293e3..eb19267678 100644 --- a/integrationTests/multiShard/endOfEpoch/epochChangeWithNodesShufflingAndRater/epochChangeWithNodesShufflingAndRater_test.go +++ b/integrationTests/multiShard/endOfEpoch/epochChangeWithNodesShufflingAndRater/epochChangeWithNodesShufflingAndRater_test.go @@ -30,7 +30,6 @@ func TestEpochChangeWithNodesShufflingAndRater(t *testing.T) { seedAddress := integrationTests.GetConnectableAddress(advertiser) rater, _ := rating.NewBlockSigningRater(integrationTests.CreateRatingsData()) - coordinatorFactory := &integrationTests.IndexHashedNodesCoordinatorWithRaterFactory{ PeerAccountListAndRatingHandler: rater, } diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index fab47004f1..2ca7bef42e 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -1738,35 +1738,71 @@ func GenValidatorsFromPubKeys(pubKeysMap map[uint32][]string, _ uint32) map[uint return validatorsMap } +// GenValidatorsFromPubKeys generates a map of validators per shard out of public keys map +func GenValidatorsFromPubKeysAndTxPubKeys( + blsPubKeysMap map[uint32][]string, + txPubKeysMap map[uint32][]string, +) map[uint32][]sharding.GenesisNodeInfoHandler { + validatorsMap := make(map[uint32][]sharding.GenesisNodeInfoHandler) + + for shardId, shardNodesPks := range blsPubKeysMap { + var shardValidators []sharding.GenesisNodeInfoHandler + for i := 0; i < len(shardNodesPks); i++ { + v := mock.NewNodeInfo([]byte(txPubKeysMap[shardId][i]), []byte(shardNodesPks[i]), shardId) + shardValidators = append(shardValidators, v) + } + validatorsMap[shardId] = shardValidators + } + + return validatorsMap +} + // CreateCryptoParams generates the crypto parameters (key pairs, key generator and suite) for multiple nodes func CreateCryptoParams(nodesPerShard int, nbMetaNodes int, nbShards uint32) *CryptoParams { + txSuite := ed25519.NewEd25519() + txKeyGen := signing.NewKeyGenerator(txSuite) suite := mcl.NewSuiteBLS12() singleSigner := &ed25519SingleSig.Ed25519Signer{} keyGen := signing.NewKeyGenerator(suite) + txKeysMap := make(map[uint32][]*TestKeyPair) keysMap := make(map[uint32][]*TestKeyPair) for shardId := uint32(0); shardId < nbShards; shardId++ { + txKeyPairs := make([]*TestKeyPair, nodesPerShard) keyPairs := make([]*TestKeyPair, nodesPerShard) for n := 0; n < nodesPerShard; n++ { kp := &TestKeyPair{} kp.Sk, kp.Pk = keyGen.GeneratePair() keyPairs[n] = kp + + txKp := &TestKeyPair{} + txKp.Sk, txKp.Pk = txKeyGen.GeneratePair() + txKeyPairs[n] = txKp } keysMap[shardId] = keyPairs + txKeysMap[shardId] = txKeyPairs } + txKeyPairs := make([]*TestKeyPair, nbMetaNodes) keyPairs := make([]*TestKeyPair, nbMetaNodes) for n := 0; n < nbMetaNodes; n++ { kp := &TestKeyPair{} kp.Sk, kp.Pk = keyGen.GeneratePair() keyPairs[n] = kp + + txKp := &TestKeyPair{} + txKp.Sk, txKp.Pk = txKeyGen.GeneratePair() + txKeyPairs[n] = txKp } keysMap[core.MetachainShardId] = keyPairs + txKeysMap[core.MetachainShardId] = txKeyPairs params := &CryptoParams{ Keys: keysMap, KeyGen: keyGen, SingleSigner: singleSigner, + TxKeyGen: txKeyGen, + TxKeys: txKeysMap, } return params diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 255f586d7a..101a853024 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -155,6 +155,8 @@ type CryptoParams struct { KeyGen crypto.KeyGenerator Keys map[uint32][]*TestKeyPair SingleSigner crypto.SingleSigner + TxKeyGen crypto.KeyGenerator + TxKeys map[uint32][]*TestKeyPair } // TestProcessorNode represents a container type of class used in integration tests @@ -1167,9 +1169,8 @@ func (tpn *TestProcessorNode) initBlockProcessor(stateCheckpointModulus uint) { argumentsBase.EpochStartTrigger = tpn.EpochStartTrigger argumentsBase.TxCoordinator = tpn.TxCoordinator - blsKeyedPubkeyConverter, _ := pubkeyConverter.NewHexPubkeyConverter(128) argsStakingToPeer := scToProtocol.ArgStakingToPeer{ - PubkeyConv: blsKeyedPubkeyConverter, + PubkeyConv: TestValidatorPubkeyConverter, Hasher: TestHasher, ProtoMarshalizer: TestMarshalizer, VmMarshalizer: TestVmMarshalizer, @@ -1422,7 +1423,7 @@ func (tpn *TestProcessorNode) LoadTxSignSkBytes(skBytes []byte) { // ProposeBlock proposes a new block func (tpn *TestProcessorNode) ProposeBlock(round uint64, nonce uint64) (data.BodyHandler, data.HeaderHandler, [][]byte) { startTime := time.Now() - maxTime := time.Second * 2 + maxTime := time.Second * 20000 haveTime := func() bool { elapsedTime := time.Since(startTime) diff --git a/integrationTests/testProcessorNodeWithMultisigner.go b/integrationTests/testProcessorNodeWithMultisigner.go index be719c3c48..3b15c5e0ee 100644 --- a/integrationTests/testProcessorNodeWithMultisigner.go +++ b/integrationTests/testProcessorNodeWithMultisigner.go @@ -2,6 +2,7 @@ package integrationTests import ( "bytes" + "encoding/hex" "fmt" "strconv" "testing" @@ -112,6 +113,169 @@ func CreateNodesWithNodesCoordinatorWithCacher( } +// CreateNodesWithNodesCoordinatorAndTxKeys +func CreateNodesWithNodesCoordinatorAndTxKeys( + nodesPerShard int, + nbMetaNodes int, + nbShards int, + shardConsensusGroupSize int, + metaConsensusGroupSize int, + seedAddress string, +) map[uint32][]*TestProcessorNode { + rater, _ := rating.NewBlockSigningRater(CreateRatingsData()) + coordinatorFactory := &IndexHashedNodesCoordinatorWithRaterFactory{ + PeerAccountListAndRatingHandler: rater, + } + cp := CreateCryptoParams(nodesPerShard, nbMetaNodes, uint32(nbShards)) + blsPubKeys := PubKeysMapFromKeysMap(cp.Keys) + txPubKeys := PubKeysMapFromKeysMap(cp.TxKeys) + validatorsMap := GenValidatorsFromPubKeysAndTxPubKeys(blsPubKeys, txPubKeys) + validatorsMapForNodesCoordinator, _ := sharding.NodesInfoToValidators(validatorsMap) + + waitingMap := make(map[uint32][]sharding.GenesisNodeInfoHandler) + for i := 0; i < nbShards; i++ { + waitingMap[uint32(i)] = make([]sharding.GenesisNodeInfoHandler, 0) + } + waitingMap[core.MetachainShardId] = make([]sharding.GenesisNodeInfoHandler, 0) + + waitingMapForNodesCoordinator := make(map[uint32][]sharding.Validator) + for i := 0; i < nbShards; i++ { + waitingMapForNodesCoordinator[uint32(i)] = make([]sharding.Validator, 0) + } + waitingMapForNodesCoordinator[core.MetachainShardId] = make([]sharding.Validator, 0) + + nodesSetup := &mock.NodesSetupStub{InitialNodesInfoCalled: func() (m map[uint32][]sharding.GenesisNodeInfoHandler, m2 map[uint32][]sharding.GenesisNodeInfoHandler) { + return validatorsMap, waitingMap + }} + + nodesMap := make(map[uint32][]*TestProcessorNode) + + for shardId, validatorList := range validatorsMap { + nodesList := make([]*TestProcessorNode, len(validatorList)) + + for i := range validatorList { + dataCache, _ := lrucache.NewCache(10000) + nodesList[i] = CreateNodeWithBLSAndTxKeys( + nodesPerShard, + nbMetaNodes, + shardConsensusGroupSize, + metaConsensusGroupSize, + shardId, + nbShards, + validatorsMapForNodesCoordinator, + waitingMapForNodesCoordinator, + i, + seedAddress, + cp, + dataCache, + coordinatorFactory, + nodesSetup, + nil, + ) + } + + nodesMap[shardId] = append(nodesMap[shardId], nodesList...) + } + + return nodesMap +} + +func CreateNodeWithBLSAndTxKeys( + nodesPerShard int, + nbMetaNodes int, + shardConsensusGroupSize int, + metaConsensusGroupSize int, + shardId uint32, + nbShards int, + validatorsMap map[uint32][]sharding.Validator, + waitingMap map[uint32][]sharding.Validator, + keyIndex int, + seedAddress string, + cp *CryptoParams, + cache sharding.Cacher, + coordinatorFactory NodesCoordinatorFactory, + nodesSetup sharding.GenesisNodesSetupHandler, + ratingsData *rating.RatingsData, +) *TestProcessorNode { + + epochStartSubscriber := &mock.EpochStartNotifierStub{} + bootStorer := CreateMemUnit() + argFactory := ArgIndexHashedNodesCoordinatorFactory{ + nodesPerShard, + nbMetaNodes, + shardConsensusGroupSize, + metaConsensusGroupSize, + shardId, + nbShards, + validatorsMap, + waitingMap, + keyIndex, + cp, + epochStartSubscriber, + TestHasher, + cache, + bootStorer, + } + nodesCoordinator := coordinatorFactory.CreateNodesCoordinator(argFactory) + + shardCoordinator, _ := sharding.NewMultiShardCoordinator(uint32(nbShards), shardId) + + messenger := CreateMessengerWithKadDht(seedAddress) + tpn := &TestProcessorNode{ + ShardCoordinator: shardCoordinator, + Messenger: messenger, + NodesCoordinator: nodesCoordinator, + HeaderSigVerifier: &mock.HeaderSigVerifierStub{}, + ChainID: ChainID, + NodesSetup: nodesSetup, + RatingsData: ratingsData, + } + + tpn.NodeKeys = cp.Keys[shardId][keyIndex] + blsHasher := &blake2b.Blake2b{HashSize: hashing.BlsHashSize} + llsig := &mclmultisig.BlsMultiSigner{Hasher: blsHasher} + + pubKeysMap := PubKeysMapFromKeysMap(cp.Keys) + + tpn.MultiSigner, _ = multisig.NewBLSMultisig( + llsig, + pubKeysMap[shardId], + tpn.NodeKeys.Sk, + cp.KeyGen, + 0, + ) + if tpn.MultiSigner == nil { + fmt.Println("Error generating multisigner") + } + twa := &TestWalletAccount{} + twa.SingleSigner = cp.SingleSigner + twa.BlockSingleSigner = &mock.SignerMock{ + VerifyStub: func(public crypto.PublicKey, msg []byte, sig []byte) error { + return nil + }, + } + sk := cp.TxKeys[shardId][keyIndex].Sk + pk := cp.TxKeys[shardId][keyIndex].Pk + keyGen := cp.TxKeyGen + + pkBuff, _ := pk.ToByteArray() + fmt.Printf("Found pk: %s in shard %d\n", hex.EncodeToString(pkBuff), shardId) + + twa.SkTxSign = sk + twa.PkTxSign = pk + twa.PkTxSignBytes, _ = pk.ToByteArray() + twa.KeygenTxSign = keyGen + twa.KeygenBlockSign = &mock.KeyGenMock{} + twa.Address = twa.PkTxSignBytes + tpn.OwnAccount = twa + + tpn.EpochStartNotifier = &mock.EpochStartNotifierStub{} + tpn.initDataPools() + tpn.initTestNode() + + return tpn +} + // CreateNodesWithNodesCoordinatorFactory returns a map with nodes per shard each using a real nodes coordinator func CreateNodesWithNodesCoordinatorFactory( nodesPerShard int, diff --git a/integrationTests/vm/systemVM/stakingSC_test.go b/integrationTests/vm/systemVM/stakingSC_test.go index 928c455c50..94d8630283 100644 --- a/integrationTests/vm/systemVM/stakingSC_test.go +++ b/integrationTests/vm/systemVM/stakingSC_test.go @@ -10,8 +10,8 @@ import ( "time" "github.com/ElrondNetwork/elrond-go/data/state" - "github.com/ElrondNetwork/elrond-go/data/transaction" "github.com/ElrondNetwork/elrond-go/integrationTests" + "github.com/ElrondNetwork/elrond-go/integrationTests/multiShard/endOfEpoch" "github.com/ElrondNetwork/elrond-go/vm/factory" "github.com/stretchr/testify/assert" ) @@ -159,13 +159,6 @@ func TestStakingUnstakingAndUnboundingOnMultiShardEnvironmentWithValidatorStatis initialVal := big.NewInt(10000000000) integrationTests.MintAllNodes(nodes, initialVal) - minNumNodes := nodes[0].NodesSetup.MinNumberOfNodes() - validators := make([]*integrationTests.TestWalletAccount, minNumNodes) - for i := 0; i < int(minNumNodes); i++ { - validators[i] = integrationTests.CreateTestWalletAccount(nodes[0].ShardCoordinator, 0) - } - integrationTests.MintAllPlayers(nodes, validators, initialVal) - verifyInitialBalance(t, nodes, initialVal) round := uint64(0) @@ -183,13 +176,6 @@ func TestStakingUnstakingAndUnboundingOnMultiShardEnvironmentWithValidatorStatis integrationTests.CreateAndSendTransaction(node, nodePrice, factory.AuctionSCAddress, txData) } - // need to add enough stakers in order to make it possible to call unstake and unbond - for index, validator := range validators { - pubKey := generateUniqueKey(index + len(nodes) + 1) - txData = "stake" + "@" + oneEncoded + "@" + pubKey + "@" + hex.EncodeToString([]byte("msg")) - createAndSendTx(nodes[0], validator, nodePrice, factory.AuctionSCAddress, []byte(txData)) - } - time.Sleep(time.Second) nrRoundsToPropagateMultiShard := 10 @@ -236,6 +222,108 @@ func TestStakingUnstakingAndUnboundingOnMultiShardEnvironmentWithValidatorStatis verifyUnbound(t, nodes) } +func TestStakeWithRewardsAddressAndValidatorStatistics(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + numOfShards := 2 + nodesPerShard := 2 + numMetachainNodes := 2 + shardConsensusGroupSize := 1 + metaConsensusGroupSize := 1 + + advertiser := integrationTests.CreateMessengerWithKadDht("") + _ = advertiser.Bootstrap() + + nodesMap := integrationTests.CreateNodesWithNodesCoordinatorAndTxKeys( + nodesPerShard, + numMetachainNodes, + numOfShards, + shardConsensusGroupSize, + metaConsensusGroupSize, + integrationTests.GetConnectableAddress(advertiser), + ) + + nodes := make([]*integrationTests.TestProcessorNode, 0) + idxProposers := make([]int, numOfShards+1) + + for _, nds := range nodesMap { + nodes = append(nodes, nds...) + } + + for _, nds := range nodesMap { + idx, err := getNodeIndex(nodes, nds[0]) + assert.Nil(t, err) + + idxProposers = append(idxProposers, idx) + } + integrationTests.DisplayAndStartNodes(nodes) + + roundsPerEpoch := uint64(5) + for _, node := range nodes { + node.EpochStartTrigger.SetRoundsPerEpoch(roundsPerEpoch) + } + + defer func() { + _ = advertiser.Close() + for _, n := range nodes { + _ = n.Messenger.Close() + } + }() + + for _, node := range nodesMap { + fmt.Println(integrationTests.MakeDisplayTable(node)) + } + + initialVal := big.NewInt(10000000000) + integrationTests.MintAllNodes(nodes, initialVal) + + rewardAccount := integrationTests.CreateTestWalletAccount(nodes[0].ShardCoordinator, 0) + + verifyInitialBalance(t, nodes, initialVal) + + round := uint64(0) + nonce := uint64(0) + round = integrationTests.IncrementAndPrintRound(round) + nonce++ + + var txData string + for _, node := range nodes { + txData = "changeRewardAddress" + "@" + hex.EncodeToString(rewardAccount.Address) + integrationTests.CreateAndSendTransaction(node, big.NewInt(0), factory.AuctionSCAddress, txData) + } + + round = uint64(1) + nonce = uint64(1) + nbBlocksToProduce := roundsPerEpoch * 3 + var consensusNodes map[uint32][]*integrationTests.TestProcessorNode + + for i := uint64(0); i < nbBlocksToProduce; i++ { + for _, nodes := range nodesMap { + integrationTests.UpdateRound(nodes, round) + } + + _, _, consensusNodes = integrationTests.AllShardsProposeBlock(round, nonce, nodesMap) + indexesProposers := endOfEpoch.GetBlockProposersIndexes(consensusNodes, nodesMap) + integrationTests.SyncAllShardsWithRoundBlock(t, nodesMap, indexesProposers, round) + round++ + nonce++ + + time.Sleep(1 * time.Second) + } + + rewardShardID := nodes[0].ShardCoordinator.ComputeId(rewardAccount.Address) + for _, node := range nodes { + if node.ShardCoordinator.SelfId() != rewardShardID { + continue + } + + rwdAccount := getAccountFromAddrBytes(node.AccntState, rewardAccount.Address) + assert.True(t, rwdAccount.GetBalance().Cmp(big.NewInt(0)) > 0) + } +} + func getNodeIndex(nodeList []*integrationTests.TestProcessorNode, node *integrationTests.TestProcessorNode) (int, error) { for i := range nodeList { if node == nodeList[i] { @@ -299,31 +387,7 @@ func getAccountFromAddrBytes(accState state.AccountsAdapter, address []byte) sta } func generateUniqueKey(identifier int) string { - neededLength := 256 + neededLength := 192 uniqueIdentifier := fmt.Sprintf("%d", identifier) return strings.Repeat("0", neededLength-len(uniqueIdentifier)) + uniqueIdentifier } - -func createAndSendTx( - node *integrationTests.TestProcessorNode, - player *integrationTests.TestWalletAccount, - txValue *big.Int, - rcvAddress []byte, - txData []byte, -) { - tx := &transaction.Transaction{ - Nonce: player.Nonce, - Value: txValue, - SndAddr: player.Address, - RcvAddr: rcvAddress, - Data: txData, - GasPrice: node.EconomicsData.GetMinGasPrice(), - GasLimit: node.EconomicsData.GetMinGasLimit()*uint64(100) + uint64(len(txData)), - } - - txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer) - tx.Signature, _ = player.SingleSigner.Sign(player.SkTxSign, txBuff) - - _, _ = node.SendTransaction(tx) - player.Nonce++ -} diff --git a/vm/systemSmartContracts/auction.go b/vm/systemSmartContracts/auction.go index 01fb064190..ee371b5095 100644 --- a/vm/systemSmartContracts/auction.go +++ b/vm/systemSmartContracts/auction.go @@ -183,13 +183,15 @@ func (s *stakingAuctionSC) changeRewardAddress(args *vmcommon.ContractCallInput) return vmcommon.UserError } + txData := "changeRewardAddress@" + hex.EncodeToString(registrationData.RewardAddress) for _, blsKey := range registrationData.BlsPubKeys { - vmOutput, err := s.executeOnStakingSC([]byte("changeRewardAddress@" + hex.EncodeToString(blsKey) + "@" + hex.EncodeToString(registrationData.RewardAddress))) - isError := err != nil || vmOutput.ReturnCode != vmcommon.Ok - if isError { - log.LogIfError(err) - return vmcommon.UserError - } + txData += "@" + hex.EncodeToString(blsKey) + } + vmOutput, err := s.executeOnStakingSC([]byte(txData)) + isError := err != nil || vmOutput.ReturnCode != vmcommon.Ok + if isError { + log.LogIfError(err) + return vmcommon.UserError } return vmcommon.Ok diff --git a/vm/systemSmartContracts/staking.go b/vm/systemSmartContracts/staking.go index bed9a7128e..acb742d0b5 100644 --- a/vm/systemSmartContracts/staking.go +++ b/vm/systemSmartContracts/staking.go @@ -276,8 +276,7 @@ func (r *stakingSC) changeRewardAddress(args *vmcommon.ContractCallInput) vmcomm return vmcommon.UserError } - for i := 1; i < len(args.Arguments); i++ { - blsKey := args.Arguments[i] + for _, blsKey := range args.Arguments[1:] { stakedData, err := r.getOrCreateRegisteredData(blsKey) if err != nil { return vmcommon.UserError From f85cc80ff82a040fd5fc3c87234ffcca65e182c0 Mon Sep 17 00:00:00 2001 From: andrei-marinica Date: Fri, 15 May 2020 15:40:29 +0300 Subject: [PATCH 66/79] fixed cross-shard delegation test --- .../smartContract/scCallingSC_test.go | 6 +++--- .../testdata/delegate/delegation.wasm | Bin 52245 -> 52411 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integrationTests/multiShard/smartContract/scCallingSC_test.go b/integrationTests/multiShard/smartContract/scCallingSC_test.go index 0bf9f0b9ac..65394010f4 100644 --- a/integrationTests/multiShard/smartContract/scCallingSC_test.go +++ b/integrationTests/multiShard/smartContract/scCallingSC_test.go @@ -568,7 +568,7 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { totalStake := stakePerNode // 1 node only in this test nodeSharePer10000 := 3000 time_before_force_unstake := 680400 - stakerBLSKey, _ := hex.DecodeString(strings.Repeat("a", 128*2)) + stakerBLSKey, _ := hex.DecodeString(strings.Repeat("a", 96*2)) stakerBLSSignature, _ := hex.DecodeString(strings.Repeat("c", 32*2)) // deploy the delegation smart contract @@ -581,8 +581,8 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) // set number of nodes - setNrNodesTxData := "setNrNodes@1" - integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setNrNodesTxData) + setNumNodesTxData := "setNumNodes@1" + integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setNumNodesTxData) nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) diff --git a/integrationTests/multiShard/smartContract/testdata/delegate/delegation.wasm b/integrationTests/multiShard/smartContract/testdata/delegate/delegation.wasm index 51a41a0896eca8f95a086c1198c6d373750d15fd..5bfed3fe06463ab3250308232c6a47fc098e2604 100755 GIT binary patch delta 17039 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 delta 17475 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 From 420e6ea3e82aae844b05c23b1953ad9003e97fa7 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 15:43:07 +0300 Subject: [PATCH 67/79] - added versioning checks when deploying SC --- core/errors.go | 12 ++ core/version/versionComparator.go | 71 +++++++ core/version/versionComparator_test.go | 154 +++++++++++++++ genesis/data/initialSmartContract.go | 6 + genesis/data/initialSmartContract_test.go | 3 + genesis/errors.go | 3 + genesis/interface.go | 1 + genesis/process/argGenesisBlockCreator.go | 1 - .../intermediate/delegationProcessor.go | 6 +- .../intermediate/delegationProcessor_test.go | 26 +-- .../process/intermediate/deployProcessor.go | 65 ++++-- .../intermediate/deployProcessor_test.go | 186 ++++++++++-------- genesis/process/shardGenesisBlockCreator.go | 13 +- genesis/process/testdata/delegation.wasm | Bin 52245 -> 52411 bytes genesis/process/testdata/smartcontracts.json | 3 +- .../smartContract/scCallingSC_test.go | 15 ++ scripts/testnet/include/config.sh | 3 +- 17 files changed, 444 insertions(+), 124 deletions(-) create mode 100644 core/version/versionComparator.go create mode 100644 core/version/versionComparator_test.go mode change 100755 => 100644 genesis/process/testdata/delegation.wasm diff --git a/core/errors.go b/core/errors.go index 7e37c61052..1b9249a62d 100644 --- a/core/errors.go +++ b/core/errors.go @@ -52,3 +52,15 @@ var ErrInvalidIdentifierForEpochStartBlockRequest = errors.New("invalid identifi // ErrNilEpochStartNotifier signals that nil epoch start notifier has been provided var ErrNilEpochStartNotifier = errors.New("nil epoch start notifier") + +// ErrVersionNumComponents signals that a wrong number of components was provided +var ErrVersionNumComponents = errors.New("invalid version while checking number of components") + +// ErrMajorVersionMismatch signals that the major version mismatch +var ErrMajorVersionMismatch = errors.New("major version mismatch") + +// ErrMinorVersionMismatch signals that the minor version mismatch +var ErrMinorVersionMismatch = errors.New("minor version mismatch") + +// ErrReleaseVersionMismatch signals that the release version mismatch +var ErrReleaseVersionMismatch = errors.New("release version mismatch") diff --git a/core/version/versionComparator.go b/core/version/versionComparator.go new file mode 100644 index 0000000000..58be5b039e --- /dev/null +++ b/core/version/versionComparator.go @@ -0,0 +1,71 @@ +package version + +import ( + "fmt" + "strings" + + "github.com/ElrondNetwork/elrond-go/core" +) + +const numComponents = 3 + +type versionComparator struct { + version string + major string + minor string + release string +} + +// NewVersionComparator return a new version comparator instance +func NewVersionComparator(providedVersion string) (*versionComparator, error) { + vc := &versionComparator{ + version: providedVersion, + } + + var err error + vc.major, vc.minor, vc.release, err = vc.splitVersionComponents(providedVersion) + if err != nil { + return nil, err + } + + return vc, nil +} + +func (vc *versionComparator) splitVersionComponents(version string) (string, string, string, error) { + components := strings.Split(version, ".") + if len(components) != numComponents { + return "", "", "", fmt.Errorf("%w, expected %d, got %d", + core.ErrVersionNumComponents, + numComponents, + len(components), + ) + } + + return components[0], components[1], components[2], nil +} + +// Check compares if the provided value is compatible with the stored values. The comparison is done on all 3 components: +// major, minor and release. A wildcard in any of the components will accept any string +func (vc *versionComparator) Check(version string) error { + major, minor, release, err := vc.splitVersionComponents(version) + if err != nil { + return err + } + + if major != vc.major && vc.major != "*" { + return fmt.Errorf("%w, expected version %s, got %s", core.ErrMajorVersionMismatch, vc.version, version) + } + if minor != vc.minor && vc.minor != "*" { + return fmt.Errorf("%w, expected version %s, got %s", core.ErrMinorVersionMismatch, vc.version, version) + } + if release != vc.release && vc.release != "*" { + return fmt.Errorf("%w, expected version %s, got %s", core.ErrReleaseVersionMismatch, vc.version, version) + } + + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (vc *versionComparator) IsInterfaceNil() bool { + return vc == nil +} diff --git a/core/version/versionComparator_test.go b/core/version/versionComparator_test.go new file mode 100644 index 0000000000..f113cca1aa --- /dev/null +++ b/core/version/versionComparator_test.go @@ -0,0 +1,154 @@ +package version + +import ( + "errors" + "testing" + + "github.com/ElrondNetwork/elrond-go/core" + "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/stretchr/testify/assert" +) + +func TestNewVersionComparator_WrongVersionShouldErr(t *testing.T) { + t.Parallel() + + vc, err := NewVersionComparator("not a valid version") + + assert.True(t, errors.Is(err, core.ErrVersionNumComponents)) + assert.True(t, check.IfNil(vc)) +} + +func TestNewVersionComparator_GoodVersionShouldWork(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "*" + vc, err := NewVersionComparator(major + "." + minor + "." + release) + + assert.Nil(t, err) + assert.False(t, check.IfNil(vc)) + + assert.Equal(t, major, vc.major) + assert.Equal(t, minor, vc.minor) + assert.Equal(t, release, vc.release) +} + +//------- Check + +func TestNewVersionComparator_CheckNotAversionShouldErr(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "*" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("not a version") + + assert.True(t, errors.Is(err, core.ErrVersionNumComponents)) +} + +func TestNewVersionComparator_MajorMismatchShouldErr(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("aa.b.c") + + assert.True(t, errors.Is(err, core.ErrMajorVersionMismatch)) +} + +func TestNewVersionComparator_MinorMismatchShouldErr(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.bb.c") + + assert.True(t, errors.Is(err, core.ErrMinorVersionMismatch)) +} + +func TestNewVersionComparator_ReleaseMismatchShouldErr(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.cc") + + assert.True(t, errors.Is(err, core.ErrReleaseVersionMismatch)) +} + +func TestNewVersionComparator_ShouldWork(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.c") + + assert.Nil(t, err) +} + +func TestNewVersionComparator_WildCardShouldWork(t *testing.T) { + t.Parallel() + + major := "*" + minor := "*" + release := "*" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.c") + + assert.Nil(t, err) +} + +func TestNewVersionComparator_WildCardMajorShouldWork(t *testing.T) { + t.Parallel() + + major := "*" + minor := "b" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.c") + + assert.Nil(t, err) +} + +func TestNewVersionComparator_WildCardMinorShouldWork(t *testing.T) { + t.Parallel() + + major := "a" + minor := "*" + release := "c" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.c") + + assert.Nil(t, err) +} + +func TestNewVersionComparator_WildCardReleaseShouldWork(t *testing.T) { + t.Parallel() + + major := "a" + minor := "b" + release := "*" + vc, _ := NewVersionComparator(major + "." + minor + "." + release) + + err := vc.Check("a.b.c") + + assert.Nil(t, err) +} diff --git a/genesis/data/initialSmartContract.go b/genesis/data/initialSmartContract.go index 50342a66b0..eb5edf52c4 100644 --- a/genesis/data/initialSmartContract.go +++ b/genesis/data/initialSmartContract.go @@ -7,6 +7,7 @@ type InitialSmartContract struct { VmType string `json:"vm-type"` InitParameters string `json:"init-parameters"` Type string `json:"type"` + Version string `json:"version"` ownerBytes []byte vmTypeBytes []byte addressBytes []byte @@ -78,6 +79,11 @@ func (isc *InitialSmartContract) Address() string { return isc.address } +// GetVersion returns the recorded version (if existing) of the SC +func (isc *InitialSmartContract) GetVersion() string { + return isc.Version +} + // IsInterfaceNil returns if underlying object is true func (isc *InitialSmartContract) IsInterfaceNil() bool { return isc == nil diff --git a/genesis/data/initialSmartContract_test.go b/genesis/data/initialSmartContract_test.go index 34b3c2db4b..5142a1f579 100644 --- a/genesis/data/initialSmartContract_test.go +++ b/genesis/data/initialSmartContract_test.go @@ -37,12 +37,14 @@ func TestInitialSmartContract_Getters(t *testing.T) { vmType := "vm type" initParams := "init parameters" scType := "type" + version := "version" isc := &InitialSmartContract{ Owner: owner, Filename: filename, VmType: vmType, Type: scType, InitParameters: initParams, + Version: version, } assert.False(t, check.IfNil(isc)) @@ -51,6 +53,7 @@ func TestInitialSmartContract_Getters(t *testing.T) { assert.Equal(t, vmType, isc.GetVmType()) assert.Equal(t, scType, isc.GetType()) assert.Equal(t, initParams, isc.GetInitParameters()) + assert.Equal(t, version, isc.GetVersion()) } func TestInitialSmartContract_AddressBytes(t *testing.T) { diff --git a/genesis/errors.go b/genesis/errors.go index bb65be3f6b..13db2c37b3 100644 --- a/genesis/errors.go +++ b/genesis/errors.go @@ -130,3 +130,6 @@ var ErrNilQueryService = errors.New("nil query service") // ErrMissingElement signals a missing element event var ErrMissingElement = errors.New("missing element") + +// ErrGetVersionFromSC signals that a coll to "version" function on a contract resulted in an unexpected result +var ErrGetVersionFromSC = errors.New("get version from contract returned an invalid response") diff --git a/genesis/interface.go b/genesis/interface.go index 5b3789248a..97d8387f57 100644 --- a/genesis/interface.go +++ b/genesis/interface.go @@ -64,6 +64,7 @@ type InitialSmartContractHandler interface { AddressBytes() []byte SetAddress(address string) Address() string + GetVersion() string IsInterfaceNil() bool } diff --git a/genesis/process/argGenesisBlockCreator.go b/genesis/process/argGenesisBlockCreator.go index a5eb879524..e691ac4175 100644 --- a/genesis/process/argGenesisBlockCreator.go +++ b/genesis/process/argGenesisBlockCreator.go @@ -41,7 +41,6 @@ type ArgsGenesisBlockCreator struct { TrieStorageManagers map[string]data.StorageManager ChainID string SystemSCConfig config.SystemSmartContractsConfig - // created component needed only for hardfork importHandler update.ImportHandler } diff --git a/genesis/process/intermediate/delegationProcessor.go b/genesis/process/intermediate/delegationProcessor.go index 1c38978fd6..6e36a62c24 100644 --- a/genesis/process/intermediate/delegationProcessor.go +++ b/genesis/process/intermediate/delegationProcessor.go @@ -29,6 +29,8 @@ type ArgDelegationProcessor struct { const stakeFunction = "stakeGenesis" const setBlsKeysFunction = "setBlsKeys" const activateBlsKeysFunction = "activate" +const setNumNodesFunction = "setNumNodes" +const setStakePerNodeFunction = "setStakePerNode" var log = logger.GetOrCreate("genesis/process/intermediate") @@ -168,7 +170,7 @@ func (dp *delegationProcessor) setDelegationStartParameters(smartContracts []gen } func (dp *delegationProcessor) executeSetNumNodes(numNodes int, sc genesis.InitialSmartContractHandler) error { - setNumNodesTxData := fmt.Sprintf("setNrNodes@%x", numNodes) + setNumNodesTxData := fmt.Sprintf("%s@%x", setNumNodesFunction, numNodes) nonce, err := dp.GetNonce(sc.OwnerBytes()) if err != nil { @@ -185,7 +187,7 @@ func (dp *delegationProcessor) executeSetNumNodes(numNodes int, sc genesis.Initi } func (dp *delegationProcessor) executeSetNodePrice(sc genesis.InitialSmartContractHandler) error { - setStakePerNodeTxData := fmt.Sprintf("setStakePerNode@%x", dp.nodePrice) + setStakePerNodeTxData := fmt.Sprintf("%s@%x", setStakePerNodeFunction, dp.nodePrice) nonce, err := dp.GetNonce(sc.OwnerBytes()) if err != nil { diff --git a/genesis/process/intermediate/delegationProcessor_test.go b/genesis/process/intermediate/delegationProcessor_test.go index 8950bd214f..5acbf7aa84 100644 --- a/genesis/process/intermediate/delegationProcessor_test.go +++ b/genesis/process/intermediate/delegationProcessor_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/assert" ) -func createMockArg() ArgDelegationProcessor { +func createMockDelegationProcessorArg() ArgDelegationProcessor { return ArgDelegationProcessor{ Executor: &mock.TxExecutionProcessorStub{}, ShardCoordinator: &mock.ShardCoordinatorMock{}, @@ -32,7 +32,7 @@ func createMockArg() ArgDelegationProcessor { func TestNewDelegationProcessor_NilExecutorShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.Executor = nil dp, err := NewDelegationProcessor(arg) @@ -43,7 +43,7 @@ func TestNewDelegationProcessor_NilExecutorShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.ShardCoordinator = nil dp, err := NewDelegationProcessor(arg) @@ -54,7 +54,7 @@ func TestNewDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.AccountsParser = nil dp, err := NewDelegationProcessor(arg) @@ -65,7 +65,7 @@ func TestNewDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.SmartContractParser = nil dp, err := NewDelegationProcessor(arg) @@ -76,7 +76,7 @@ func TestNewDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilNodesSplitterShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.NodesListSplitter = nil dp, err := NewDelegationProcessor(arg) @@ -87,7 +87,7 @@ func TestNewDelegationProcessor_NilNodesSplitterShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilQueryServiceShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.QueryService = nil dp, err := NewDelegationProcessor(arg) @@ -98,7 +98,7 @@ func TestNewDelegationProcessor_NilQueryServiceShouldErr(t *testing.T) { func TestNewDelegationProcessor_NilNodePriceShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.NodePrice = nil dp, err := NewDelegationProcessor(arg) @@ -109,7 +109,7 @@ func TestNewDelegationProcessor_NilNodePriceShouldErr(t *testing.T) { func TestNewDelegationProcessor_ZeroNodePriceShouldErr(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.NodePrice = big.NewInt(0) dp, err := NewDelegationProcessor(arg) @@ -120,7 +120,7 @@ func TestNewDelegationProcessor_ZeroNodePriceShouldErr(t *testing.T) { func TestNewDelegationProcessor_ShouldWork(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() dp, err := NewDelegationProcessor(arg) assert.False(t, check.IfNil(dp)) @@ -133,7 +133,7 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) t.Parallel() expectedErr := fmt.Errorf("expected error") - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { assert.Fail(t, "should have not execute a transaction") @@ -158,7 +158,7 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) func TestDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *testing.T) { t.Parallel() - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { assert.Fail(t, "should have not execute a transaction") @@ -195,7 +195,7 @@ func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { pubkey2 := []byte("pubkey2") pubkey3 := []byte("pubkey3") - arg := createMockArg() + arg := createMockDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { isStakeCall := strings.Contains(string(data), "stake") diff --git a/genesis/process/intermediate/deployProcessor.go b/genesis/process/intermediate/deployProcessor.go index 084c063e09..edb1d79181 100644 --- a/genesis/process/intermediate/deployProcessor.go +++ b/genesis/process/intermediate/deployProcessor.go @@ -9,8 +9,10 @@ import ( "strings" "github.com/ElrondNetwork/elrond-go/core/check" + "github.com/ElrondNetwork/elrond-go/core/version" "github.com/ElrondNetwork/elrond-go/data/state" "github.com/ElrondNetwork/elrond-go/genesis" + "github.com/ElrondNetwork/elrond-go/node/external" "github.com/ElrondNetwork/elrond-go/process" vmFactory "github.com/ElrondNetwork/elrond-go/vm/factory" ) @@ -18,35 +20,45 @@ import ( // codeMetadataHexForInitialSC used for initial SC deployment, set to upgrade-able const codeMetadataHexForInitialSC = "0100" const auctionScAddressPlaceholder = "%auction_sc_address%" +const versionFunction = "version" + +// ArgDeployProcessor is the argument used to create a deployProcessor instance +type ArgDeployProcessor struct { + Executor genesis.TxExecutionProcessor + PubkeyConv state.PubkeyConverter + BlockchainHook process.BlockChainHookHandler + QueryService external.SCQueryService +} type deployProcessor struct { genesis.TxExecutionProcessor pubkeyConv state.PubkeyConverter getScCodeAsHex func(filename string) (string, error) blockchainHook process.BlockChainHookHandler + scQueryService process.SCQueryService emptyAddress []byte } // NewDeployProcessor returns a new instance of deploy processor able to deploy SC -func NewDeployProcessor( - executor genesis.TxExecutionProcessor, - pubkeyConv state.PubkeyConverter, - blockchainHook process.BlockChainHookHandler, -) (*deployProcessor, error) { - if check.IfNil(executor) { +func NewDeployProcessor(arg ArgDeployProcessor) (*deployProcessor, error) { + if check.IfNil(arg.Executor) { return nil, genesis.ErrNilTxExecutionProcessor } - if check.IfNil(pubkeyConv) { + if check.IfNil(arg.PubkeyConv) { return nil, genesis.ErrNilPubkeyConverter } - if check.IfNil(blockchainHook) { + if check.IfNil(arg.BlockchainHook) { return nil, process.ErrNilBlockChainHook } + if check.IfNil(arg.QueryService) { + return nil, genesis.ErrNilQueryService + } dp := &deployProcessor{ - TxExecutionProcessor: executor, - pubkeyConv: pubkeyConv, - blockchainHook: blockchainHook, + TxExecutionProcessor: arg.Executor, + pubkeyConv: arg.PubkeyConv, + blockchainHook: arg.BlockchainHook, + scQueryService: arg.QueryService, } dp.getScCodeAsHex = dp.getSCCodeAsHex dp.emptyAddress = make([]byte, dp.pubkeyConv.Len()) @@ -125,7 +137,7 @@ func (dp *deployProcessor) Deploy(sc genesis.InitialSmartContractHandler) error ) } - return nil + return dp.checkVersion(sc, scResultingAddressBytes) } func (dp *deployProcessor) applyCommonPlaceholders(txData string) string { @@ -144,6 +156,35 @@ func (dp *deployProcessor) getSCCodeAsHex(filename string) (string, error) { return hex.EncodeToString(code), nil } +func (dp *deployProcessor) checkVersion(sc genesis.InitialSmartContractHandler, scResultingAddressBytes []byte) error { + if len(sc.GetVersion()) == 0 { + //no version info, assuming deployed contract is up-to-date (let contracts that do not provide "version" function + // to be deployed at genesis time) + return nil + } + + vc, err := version.NewVersionComparator(sc.GetVersion()) + if err != nil { + return err + } + + scQueryVersion := &process.SCQuery{ + ScAddress: scResultingAddressBytes, + FuncName: versionFunction, + Arguments: [][]byte{}, + } + + vmOutputVersion, err := dp.scQueryService.ExecuteQuery(scQueryVersion) + if err != nil { + return err + } + if len(vmOutputVersion.ReturnData) != 1 { + return genesis.ErrGetVersionFromSC + } + + return vc.Check(string(vmOutputVersion.ReturnData[0])) +} + // IsInterfaceNil returns if underlying object is true func (dp *deployProcessor) IsInterfaceNil() bool { return dp == nil || dp.TxExecutionProcessor == nil diff --git a/genesis/process/intermediate/deployProcessor_test.go b/genesis/process/intermediate/deployProcessor_test.go index eab34ae3fc..253ae1a5e5 100644 --- a/genesis/process/intermediate/deployProcessor_test.go +++ b/genesis/process/intermediate/deployProcessor_test.go @@ -12,17 +12,25 @@ import ( "github.com/ElrondNetwork/elrond-go/genesis/data" "github.com/ElrondNetwork/elrond-go/genesis/mock" "github.com/ElrondNetwork/elrond-go/process" + vmcommon "github.com/ElrondNetwork/elrond-vm-common" "github.com/stretchr/testify/assert" ) +func createMockDeployArg() ArgDeployProcessor { + return ArgDeployProcessor{ + Executor: &mock.TxExecutionProcessorStub{}, + PubkeyConv: mock.NewPubkeyConverterMock(32), + BlockchainHook: &mock.BlockChainHookHandlerMock{}, + QueryService: &mock.QueryServiceStub{}, + } +} + func TestNewDeployProcessor_NilExecutorShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDeployProcessor( - nil, - mock.NewPubkeyConverterMock(32), - &mock.BlockChainHookHandlerMock{}, - ) + arg := createMockDeployArg() + arg.Executor = nil + dp, err := NewDeployProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilTxExecutionProcessor, err) @@ -31,11 +39,9 @@ func TestNewDeployProcessor_NilExecutorShouldErr(t *testing.T) { func TestNewDeployProcessor_NilPubkeyConverterShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - nil, - &mock.BlockChainHookHandlerMock{}, - ) + arg := createMockDeployArg() + arg.PubkeyConv = nil + dp, err := NewDeployProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilPubkeyConverter, err) @@ -44,24 +50,30 @@ func TestNewDeployProcessor_NilPubkeyConverterShouldErr(t *testing.T) { func TestNewDeployProcessor_NilBlockchainHookShouldErr(t *testing.T) { t.Parallel() - dp, err := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - mock.NewPubkeyConverterMock(32), - nil, - ) + arg := createMockDeployArg() + arg.BlockchainHook = nil + dp, err := NewDeployProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, process.ErrNilBlockChainHook, err) } +func TestNewDeployProcessor_NilQueryServiceShouldErr(t *testing.T) { + t.Parallel() + + arg := createMockDeployArg() + arg.QueryService = nil + dp, err := NewDeployProcessor(arg) + + assert.True(t, check.IfNil(dp)) + assert.Equal(t, genesis.ErrNilQueryService, err) +} + func TestNewDeployProcessor_ShouldWork(t *testing.T) { t.Parallel() - dp, err := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - mock.NewPubkeyConverterMock(32), - &mock.BlockChainHookHandlerMock{}, - ) + arg := createMockDeployArg() + dp, err := NewDeployProcessor(arg) assert.False(t, check.IfNil(dp)) assert.Nil(t, err) @@ -72,11 +84,8 @@ func TestNewDeployProcessor_ShouldWork(t *testing.T) { func TestDeployProcessor_DeployGetCodeFailsShouldErr(t *testing.T) { t.Parallel() - dp, _ := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - mock.NewPubkeyConverterMock(0), - &mock.BlockChainHookHandlerMock{}, - ) + arg := createMockDeployArg() + dp, _ := NewDeployProcessor(arg) expectedErr := fmt.Errorf("expected error") dp.getScCodeAsHex = func(filename string) (string, error) { return "", expectedErr @@ -91,15 +100,13 @@ func TestDeployProcessor_DeployGetNonceFailsShouldErr(t *testing.T) { t.Parallel() expectedErr := fmt.Errorf("expected error") - dp, _ := NewDeployProcessor( - &mock.TxExecutionProcessorStub{ - GetNonceCalled: func(senderBytes []byte) (uint64, error) { - return 0, expectedErr - }, + arg := createMockDeployArg() + arg.Executor = &mock.TxExecutionProcessorStub{ + GetNonceCalled: func(senderBytes []byte) (uint64, error) { + return 0, expectedErr }, - mock.NewPubkeyConverterMock(0), - &mock.BlockChainHookHandlerMock{}, - ) + } + dp, _ := NewDeployProcessor(arg) dp.getScCodeAsHex = func(filename string) (string, error) { return "", nil } @@ -113,15 +120,13 @@ func TestDeployProcessor_DeployNewAddressFailsShouldErr(t *testing.T) { t.Parallel() expectedErr := fmt.Errorf("expected error") - dp, _ := NewDeployProcessor( - &mock.TxExecutionProcessorStub{}, - mock.NewPubkeyConverterMock(0), - &mock.BlockChainHookHandlerMock{ - NewAddressCalled: func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) { - return nil, expectedErr - }, + arg := createMockDeployArg() + arg.BlockchainHook = &mock.BlockChainHookHandlerMock{ + NewAddressCalled: func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) { + return nil, expectedErr }, - ) + } + dp, _ := NewDeployProcessor(arg) dp.getScCodeAsHex = func(filename string) (string, error) { return "", nil } @@ -136,64 +141,71 @@ func TestDeployProcessor_DeployShouldWork(t *testing.T) { testNonce := uint64(4453) testSender := []byte("sender") - lenAddress := 32 executeCalled := false testCode := "code" vmType := "0500" + version := "1.0.0" accountExists := false - dp, _ := NewDeployProcessor( - &mock.TxExecutionProcessorStub{ - GetNonceCalled: func(senderBytes []byte) (uint64, error) { - if bytes.Equal(senderBytes, testSender) { - return testNonce, nil - } - assert.Fail(t, "wrong sender") - - return 0, nil - }, - ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { - if nonce != testNonce { - assert.Fail(t, "nonce mismatch") - } - if !bytes.Equal(sndAddr, testSender) { - assert.Fail(t, "sender mismatch") - } - if !bytes.Equal(rcvAddress, make([]byte, lenAddress)) { - assert.Fail(t, "receiver mismatch") - } - if value.Cmp(zero) != 0 { - assert.Fail(t, "value should have been 0") - } - expectedCode := fmt.Sprintf("%s@%s@0100", testCode, vmType) - if string(data) != expectedCode { - assert.Fail(t, "code mismatch") - } - - executeCalled = true - return nil - }, - AccountExistsCalled: func(address []byte) bool { - result := accountExists - accountExists = true - - return result - }, + arg := createMockDeployArg() + arg.Executor = &mock.TxExecutionProcessorStub{ + GetNonceCalled: func(senderBytes []byte) (uint64, error) { + if bytes.Equal(senderBytes, testSender) { + return testNonce, nil + } + assert.Fail(t, "wrong sender") + + return 0, nil + }, + ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { + if nonce != testNonce { + assert.Fail(t, "nonce mismatch") + } + if !bytes.Equal(sndAddr, testSender) { + assert.Fail(t, "sender mismatch") + } + if !bytes.Equal(rcvAddress, make([]byte, arg.PubkeyConv.Len())) { + assert.Fail(t, "receiver mismatch") + } + if value.Cmp(zero) != 0 { + assert.Fail(t, "value should have been 0") + } + expectedCode := fmt.Sprintf("%s@%s@0100", testCode, vmType) + if string(data) != expectedCode { + assert.Fail(t, "code mismatch") + } + + executeCalled = true + return nil }, - mock.NewPubkeyConverterMock(lenAddress), - &mock.BlockChainHookHandlerMock{ - NewAddressCalled: func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) { - buff := fmt.Sprintf("%s_%d_%s", string(creatorAddress), creatorNonce, hex.EncodeToString(vmType)) + AccountExistsCalled: func(address []byte) bool { + result := accountExists + accountExists = true - return []byte(buff), nil - }, + return result }, - ) + } + arg.BlockchainHook = &mock.BlockChainHookHandlerMock{ + NewAddressCalled: func(creatorAddress []byte, creatorNonce uint64, vmType []byte) ([]byte, error) { + buff := fmt.Sprintf("%s_%d_%s", string(creatorAddress), creatorNonce, hex.EncodeToString(vmType)) + + return []byte(buff), nil + }, + } + arg.QueryService = &mock.QueryServiceStub{ + ExecuteQueryCalled: func(query *process.SCQuery) (*vmcommon.VMOutput, error) { + return &vmcommon.VMOutput{ + ReturnData: [][]byte{[]byte(version)}, + }, nil + }, + } + dp, _ := NewDeployProcessor(arg) dp.getScCodeAsHex = func(filename string) (string, error) { return testCode, nil } sc := &data.InitialSmartContract{ - VmType: vmType, + VmType: vmType, + Version: version, } sc.SetOwnerBytes(testSender) diff --git a/genesis/process/shardGenesisBlockCreator.go b/genesis/process/shardGenesisBlockCreator.go index a9cba7c987..3e2aa82ef4 100644 --- a/genesis/process/shardGenesisBlockCreator.go +++ b/genesis/process/shardGenesisBlockCreator.go @@ -444,12 +444,13 @@ func deployInitialSmartContract( return err } - var deployProc genesis.DeployProcessor - deployProc, err = intermediate.NewDeployProcessor( - txExecutor, - arg.PubkeyConv, - processors.blockchainHook, - ) + argDeploy := intermediate.ArgDeployProcessor{ + Executor: txExecutor, + PubkeyConv: arg.PubkeyConv, + BlockchainHook: processors.blockchainHook, + QueryService: processors.queryService, + } + deployProc, err := intermediate.NewDeployProcessor(argDeploy) if err != nil { return err } diff --git a/genesis/process/testdata/delegation.wasm b/genesis/process/testdata/delegation.wasm old mode 100755 new mode 100644 index 51a41a0896eca8f95a086c1198c6d373750d15fd..5bfed3fe06463ab3250308232c6a47fc098e2604 GIT binary patch delta 17039 zcmdUXd3=?{_4mx&o7|h+giJz!Y`}9bTS8bOV8SAp35yG$;DS{|jUfUd1eyeqF5b&3 z$`%+zR8&wFQG!cwt=eEkajDjpR@AoQQl)Aswzi^TdB11od2VjNzOSG6_ty`bJI`!q z&N*|oInO-3b(8NGxBDLM$MspfwIr>fac+I(jOvR~RI^lHb=~zT*Up-8UR~qF`L!%S z^;BEGWX!DVS)iprOyh%=i6tUA7!V>D4A6ff7zktpgEEK))J2D69!TaqlXK1l{sjYi zw=X{s2&D1=XZm$tm%c&2-xmz}lZEgHeIg4*vOhV>XZo{) zS-z|w)pU`6Uip*1Y-OP+Q>G03KB;f=oa#Aq>lX?ZxW2l+Vbrx{b&d6vRgD)esH?7LE&6qTKHsZ9^%q1Rgi@Qd)myr zpngnsZS{;w@VbHhf`?{QM;kAgKZgJ{uxEG(kmA*6c`DYbsBIWuy|95j$I}Uu`E$I6 zU-DFp_G+!D5ms2Nv6}7UDHwcdLv{Um)7kU911jTY)z*5r{E7$BV)2T;z>~~Owx2^3 z0OFkLy6T2m4eUi8nD4UTB_0ItW?fIPU*;L!vp4cpo;tnSYh4Pt-UQk&-y@9>KGq0|<&sSsq)pf+&-|)<;xpU^t zZ>(0ewcf}#^|9p6(ckj4s@lp~bG+8y@ob{GuG(dLMP+SeT~#$Z$a5FWYMeQ}zH-6o zoxkUqbFaIuy58^tJAZLyZ8iHt+a`NWZ}Ieb^Xsc-RyGiaAsC0!c(AInwzi_OYBqaY zUm55+^+L`R4;A0=SALxTlaE>W0KY|i$^XTdiAmF@UO9e|m@sd|e1*n_LaFrpTm41{ z#qZad8Kcs68Nfo7)W{urYQ`BradpNd@mWm2mr;`XjhXdu8 zE5i9fJtDOmCS8$w8Gav4?ZtQNL#e}xEyAKulv{*_YGpME82gl?PAs+vpB1_kbJvF| z@Ec0$slN{O0gu9IT~j*%T}L=vey)e5trSZ)=snB2>%XLR;z#tiX}vH$oZc(x9v@GN z>i1K6XkV}^e^`fuRs2D{EI0=JuLR2t)bSm55G{&_{a_bpot{$2Z`P|*@^vS9rDMIQ+0T%0udpx};-2(X>Zj)$tm!{vqAk@ml^1Jt(`^InO;r7?sFX zi(@gyLL?aA#d2Z{3#Fl^9C?%3@>HgnTwxw_IFBllW7J|S!sN~R?(Do_w@@w55upqN z1v0wQw1hfie8T8e)atNM7)uq39JO12kv(Wsu3Z{^F(zN6Uv-lISn+Y8eC&~m8pKvp zdjy!ApRX`JKh)9AdQn$)x+?8BG0zbsgfF+e+UWvO{Msh8$Yz?wLQc?0RnPplmX~7ZZjAUUoE19_a*BmHq=B?&Y=oDJ zY!bem5r3(WhG}G6Btg?p7JLWUd%Wv){DAJ-&B61iZoT;1`rPh)_n5TgOaV z4Q!R~yX6P^P`858qf`rv5bal~@S_l=;8Y5eN9?$EPwy`>FgEGF-Mi|lZiNzqi+VOFa+RP7VJ$%&M> z;IUajqc0w6(uE05_+US4Ys^;4t@?;_DFBTMcjJH4)51M74zFv)_GGFrsg&>PrtoE8 z&yg@K*C$fMKhcvTrRgp<7OI|H91ed*I0H5-6**+%i+sT{pF{&pJBPyT(z>{h{`Q)_ ze5vkTc}B`|tCsQu-4w|^a|P8PlL2C=#1qW{QGX^T8g0b}{?Sy7nIwpR(tnQR!`FNh z31@kF;0kG4ZH*q$Be&=mgp|=FPf4ZGv$3JIK@p1b8+%{?$lan>_Q;JMX7WD51BzZj z?J;<*nb@hryhe$dun&*N@#wFIsT8USkG}eF5*}OafMh)0k4Mhav2Qjr^Tn z*R$tP!XQY{2-jdu5ocvSvKQ2j4Y2L9W*}!HINBXi#1Hc_U#tFG&*2%zA8L(Z+h9gQ zPOAJ$m-gxwy`Psc<|J95L==EBX4?!vYLny|hhv;@(uTA3v}K{;Y#o)U!&wt|Qqwu; z4UxGc0@Mpj%u0Wx5h787U4;>-gO{ksVrJfPdL|bU z#e@wQfNB$Ax57SyyQQK@fF`rk_@ym4K!}pHv)jLdU|EMKZA^iVW6a$k%S%W=Bnd31 z6^ejTB)!Zx&mo(vlBrq$ws+SkBuxIEV8ab2f{2;z0Ejq%80eY@tWqFK7aBw$3@J6V zD}+@WAc~)8klIT-5qBSOLo|}s2R>p0*utC~rqW1sNYK-2iUdO=;ju;E)aR0Z&yXLM z?_iUl^-%V3GPEA{m;42+EjbIndd&{ffx@|gPibhVQ4cKWq}Lao&tKMmDva>O>x**u z5}jLATo79dh$=~*Ad)c|QN=RT)LEX;*A$IL7_zNsY}$8jw+Z6@Rdg2rP7msVhaN{@+STJ;zE9t{!eipeslW`&R%0WK{Ih}+v7l8uGQD{%i&FWVZR}LpEINf zT-K8BQTt6(j@yL&3aXPQPoAw84(P-0(_06WMLkAGDKt!m(9~d$g>qc<(-2{!dMdk2 z?AwlALY=}cLEUj~32XP#`=W9&saKfECHmcg1y`>%OcHRV z>a8_2ql0XvrcfqRM@>VD+&~RGLtPN)$z?Pfjtdd*a(Z;k$iK87naz~jqNkMfkSpv! ziZr;xupc*R+3h?mqL|6<{BA0fOZgpCiV=JhA}~8QaVAheBM6Zn8$?(#R3-@#@|S1y9cFM-eu^i# z+6H2c;V0;zji8nakbBawudCX;wiO#hYi!b&4eHj})dCe0ZWtN*kmKO`&fvTrf1#lW zmmV>^HUS1$>jMX&UO~e^J^8F|DfbwV`RWgP)R2N{6poWuLd;BF$p?EMNhPSQ>o zs#b!99TRc&#{#z)k)t@6%a!z8DuSp00=4-JASgGaL7x~GLHyYLobrTKUl}$$)4~M+ z53ateyg%a2(?<3@Z6r-Hz_BpI^|wU+%0V9a%q8DXGH4}>Y_UuJ?7`ilaq?Zx`UwSB zqaXl|@z)dp5m(IK_?;x;N`SZ$*y%us!6V^t#b92dfd zo%*$NvcZz~+p%QSkhAhE$OJ}{fi%-~>p2d1bJ~>Xf1koazw?Xagg}?a)l)VRauEU5 zeTt}1J8x>GJthSN5sRo-zC=9~P{?&u2gU2D#0W06ouAI2RdT7V$PHAIL^}u_yY@ybh#9vM(nhoJUku-x#0l1$Vf+ZqtUqai2W zKoCnDtZAl9LLY*t3sE4}1F<`eXz(tE5=fwljpk7(PiQvj%qu!Zq2;bbAy_tu3X&|J zyw&9jMQ%pbK`NOsvTv?+^<_|4>D&^DBUPn5%-Y zz`5RvDx~a1>Q_093MKS9XTB1Ra03VFtZG~U7^)7$Yv!m9J8Dc6%u#5;Fs$gF`C8fR z2(!FYKDo&-oPn3}_O{16=#jh|g5F7^vU9D=qdG#!lY|T&3v1*-{qs@d`RDrOQDtBc zKRdUFXI=Ii>yirACs-F#*{(;PJv{Ge(;q^%0z6+s5aDqQ_w>563wzve%zv8PZgC=| zG5QpgJ4_2D_x^bH!mRgbCTS&1Tm%Y>WA%*ku~F>t>&>lTnYYEIpkLl)sq&7*WCFlj zH)L=`MbqnU{!2C)5=|KKYlBIuD=H^B_j`<#vm?TlNyxa>d3h(T5e@s|iy-en{)b6( zCZ}D8TQU0$^WvAA4Nma?px(H6jD@|mrYVGG@?8-QaQg`-I&D$+Jv1$XxHnD!o~^h5 z`5bi8L~1iO4gst2OFCs+cN{TEalud8b;yme^du#CmadkC@)8q#mQjWP;KnQ&ZA%DH)*>C-XSoKuX~>dWi8zSX(#-7WeTL=S;%X-V4U6kPjl2*Bu#*vCZLX=pltUKiJY}k|)asa4 zxz3%QgY9tbupt2FOLuCpMmT=m_ssl3LasNXN#qQ>!k~k-szH{_Aq})FkJ=%v9n(i~EKhjT^jv1W2 z1!p7*jt=9DL;)#6&+U5in2|WLzB8sQ;>N&E@=ok+T*)!Wn06@sn|korL9iUxjqRT5 zS&q$X_1dv#@wm|`UKqJw zKRYfD3mrl{_J#g-To3-)>9JOaR^n_JvVx6-fqD3x5)3;n?C87CZh#r&KE?wb_!5`- zAa9>;I`<&oqpQywmJ;_#dgpoNVe9A2zIn`0zw!1kG=+2hMPuSBC*A$^Rb@GRwZ@D_%0=@XcTeIvqd%sh)jDrlCSC=GLUi|9iUkVxgD{7 zQs)f2qR*}DgYW7-(7!%l76e+DS$Oz3^u8m>o0@A3)7 zE^po4lsk3ngliy?;fc9Dc9Z8;d1{v_eTK+*NNzZ_T|1X{()APjj=ah4eZu09e5?DR z0w&uLVm+SRNK;IwzUP8m{f~(`Q9F!#`)qcUJIwBgUEeT>{1u6iZ8}EdC`{=YW@_Uy zAZ=bh$X#X^kn9|r&Q%fmp0<4m)Bw|yfw#<#b|4wJmH_1eXlq>NPs7~?;ud#6X-}9v zw?}K5F+Mg4Y%V1 zIEcV4o{*3*#I?F~Qg4Kw(oe=E?cF zyJ;MW77Q32v>bkJdJ?)<=w~Mv3`E}91enG`m`OFB#v<-?8(eV|>QNoMsQb7T^jbm2 zt@RbKR|uQUC+wC_XdmQjEq-+8dyY*a}hRJ3>Le+F&REYvBth@4y_qNh0Q9 z7>1M~+pks{tI|!i?J6i~GcSbeQs7#MNkKzEU%Z)hc>~-Nu?BR8H<&JVZLARV?uTf_ z9<+HOLLP^NkBPS?wrZy}zcyMURF7~HQ9?MG)DT4B{3K6>&~YjsJVHUB<%1m~Jq`Me zug01~Xb|3yUvNq9Q!MW;Sl&V$T6SMjHqv@b2%i^e5#J~mGYvcR>`QwiPMS0&M@X%AUz&Hy%1yf8lpbb4RR^0zFmIS)5cR$(LoR&Ys1CC> zH_@mv)eC3BW7f>j`(EarAh>j+QnZ*rAI7!WS`y^J@475sUwv7U8%DG@_TDO+Xw3>X z8Actq6V$CH7ee<<0MS5*?oSed_K6f``RkhG_Henyo_^a?@T!3!yde`Ytc2YiVlp8C# zAxu2|;&P8dX?Kj}UOYvF_Nblg=7A_Se3;f!S@M8o^eGt}c1i}v*4r{TChqq#IBf|W zGRiiA0|A^zsTm)R5_p%RCtuz_nvlscfv%UyVJe=zaM16W0@Chy z`o^5insntAxq07{sIjvi(_60S5pDNs=K$S}k!vYf1)@l3lE?7L&9pgrbn-Pleh7(` z&5#c9H1D9k1-bclGMnI}pvTrp{n_j@pd&q3DlSpFVroxZbDA-AM7rmM9tK6*^g~lS zrN%waefssO`TSA+>C~?LuR3_;g!1;5JanoWJbg0=K@5TWJ~?5I-kXezG&ta8w|Y}= zxN>+j?$OVUB&Fkx@GWMN>WXj+#*)$raHRroCt-9!G$!JLP#iM&4d1)biYHD?P$-v%C(s%oS?^Qjx@;OqxOu#qXc=9)0~>s8kjpKV=WvXg|Rh<>I{fS=!5;UvA32i@l_ z-Ww386!8sO@X8`xSvg)D(0Whhpuk~G966#tsq8wWUDRkzv`jGl*6ee*0Bia|hTN!! zUfU~R@`G}Zo_?(tO~;R;KlHHhq>*0aV^29OD1q=vz3KLLHqryD<63Tco0VUZC#%ys zRF!viJ3^ee@317H?z&ZI(kCupxK20_fg`GXkU+L2TUV_FgAlj>${u6D>o4@us>!7$ zD3Cj8aM&+zH~dB#?`Knh?i=nLs3K`e0=hahePBYyc=Yt*s&>eV1c#{nr0bs(Eai9< zV|_1}#~I%;ev8Wlybkozvv^EQ&%QZ*Xf)=ILT1I24k)&32~Rs%nG~gaD2#aLrgmQ3 zW+mMroxLI6$<^Q#dYZ>m${mopNU*Sof2veMcwp%i<0;HeJ=oKkRY2~#Mvx?>gbT3V-Vvvv_=uG}=DoAQH4 z@zN6}jX4FeNU7*)jxnbFd_QT1 z7JJYkN^I3Q8OxW(?TIDcy%Fb$mj)E1U>M9@S^e%i){!>(`Ia z=hmmStebZ}ALI_k3l18b?kr@_E_a}-v-0s^zZnT&TJx9lOWJmb*3>8Fdtk1+zGUd>U~tVFZ$FVIO2o5trl)`%c+X2a`ahBZv;E3kn*>&CNb@L(hhWn%FpOtJC~?zs zN{mRS@qr8bB?#ri3$r_(lKL=b_W#dOLcOhjvao-<1rl`t%Sm<6yc#J}FHnhlzVavG z4EMDxF$?e3j_LBBjD#59_>W6uB2fu?sWQU zR3FDT8>9@4ot?9i$cOKPA310^@+tkwZ}i$&DKLF8c4p7dsijmD5*d)uQZW=|&l+Ws zqp9*`-F;DB-_@3t@&misYA<2023zPyOyxNJ;--GpqRss1`o&}DC#3yp&DRPBT9iqdqDu(jEYcbBItui}?AHV!Uk6P0w z`77#6*YDrkNypZt_Hr*f=Qx5c|E7Vbd+ECgdPQqqQIpeuSwFOM)kejbe)byeP6e2)p<>2;{I*=;-r;;;sW00#`PJszF+>%qqo%x9sHV--@R*SQ zCSD*{0^?0+cxqB%-^Z5JS6)=;7?ir90H4p!^ z#GY*vaLv=V_0Ib(4YB@Wy*1MYjZ(Q@W4Wq>;(4LIUM10N7-2YCx&L}tL?vsaJVF(tj-%6jLH8~AP7 z**Tuy)>6CkZq7Hggm%3}#fJ}E%F|yx8}>OCYh|ImWykf{-Qhmfwe|R%cVJ!hf`+Pr zw$gt=Wy75Q^$m$ty>s_KeQ5V8T$itIp3!M4mn?%ZHVI`2Wj2#+jDEj4A0MNA*W3la zo%R%G9*p-gmV!|S_2fM_CzT8sG@zvAojvPC8hy;`)Xl~JrdPMz{75>VKDVxRp);30 z>~^Xu>m2WEUuS;&TVUr}`!Vq8EoScY_&3=GfcYZWG2cQv_!8M^z(>J)bD>3 zk(!-K-*hoHB(){^alum^T+T^Gy?01wJux8VN2t=II(^;~#nJaV*_uDd*g&*S9WY?P zG?ZUr6z#^#ZvWskyTne^JD~kBlzx;?p(M<`esA7M%&({`^_`=(7*-r7gEV z_bZXP6lnB7>v;SX;%}**vu{b!@h+CB!OnJp;ST)+<5ADUsFh$EA^D!peZH7ux#t(9 zjh%4Og%^ymU!1qR_AsE$!60a)RvnbP0zKqg`(#g^P`PI=*POfAVP@ROo zZq!V5&G+a2V7-{Szt;~QyKjGfr&_E)t6hY@eEgZZ{$l@vq$PQhjn#8r925P4I@zD( zc3?w2^!A3v0rd@s0N{LpJPRDc$4YGA%(-)_2UgZiudkjp$5rP4r=kOBkqZ_7PZ3wo kpH)Yo88g@c=v(+BPFZYMzciRP>U}Sr$M?2`4y5}355F0ybN~PV delta 17475 zcmdsfd3;nww*Rf_PP)_GNh++_fZNTM5Fk-7Vbv7KqTq_6PeBNw!89Rg5=0!eo7D~3 zN)bm91Qe9rphjghDq=<*2S>(r-iRY_V8)GcoEcPRc;8cXZzlnr&+qqp@2?*->AJO@ zI_K2c>eRiy@Sx}ZwVvI5Ss-m%)yxZO>MxpGt$MKocED7xIKS#9%jb#K+!U&-pHo{g zGdcl9)Cx4@^T}+$V!n{4`h7mm{eB-T$jJCxqkcHHO7;Hk{(=k40H^W(3b%J6pPKELYY zz2ThZmzu0#+>*NV{W_&Eb#`?2oZ9)^@>bPU)muB6m>I1fIj5$+wxY8Bl6f`JT5FH` z$eR~`ishh3&aJGknp5KrkkhBvM(gUV2Hkl@)$Hhq=nPOgdQNR+^vasL`ifamYcC67 z=EZZSM<-lg0WLhvGEtvEeV0aSsoi>pW!9b6^sL5Y)Xg_UE9;}vC&V?VMm_c7+Vi8; z(U}$CX`S^P3lMY-r_Oqw1pvscy}&Z2pmRzM)|gUVQCDy6)1yaJ*NuzLud{w(FspUz zFY4KD?IqM`RbW~ljayAD4Y01Pi`HH+-FlgIKxJ$dZEsa&MfK&;c@?$O>#SE;-jB6| zADYfrS@;nAqh-C$AYH(3OtdCiS5;>URdXb(@j zlv$Dmi{>9=|6t#+QMWw7?&5!C-?GL0((5Ko9+%+b&%f-}1Y5v9V@KG3u|Kj?>~nU4 zeb0ViC)q#Qzt~#-Apbdkh(E&b;}7$7Jn*MxC}+SLVTlC(S;6%lmJ;utNT`V!!`Wta zUq&T+Or6L$pFOUIXO`pl_RMh^TWF|cVQXTIBW1ux!ibX!~5l>TL0H z+bZCe^o>qOmv~n<2Ltr{TlIEeV)3IZni5v5pM`1C9}|z!08HWqyj=RmV3J3&SlEN! zCMzZ$R}+F)0f%kDp6m(rPH=FMo{${Q-Ejma#DYOgx8>SJSVKIi&Iw(Kx%Y%d;P>s& zIJQOQrgu@J)0gr_r9NHKO?{c(ksVc@jGh=!n9);x>KmQA!(e1^vJFmL+JuYrOTbv< zAKPA(dHlSbmwU=>50(TWPpIGf!|c@Rv?DRvCYWq=P&_ZKM6FI6 z#&)S+r=1(xO@lyENeoQR37iGA#sx0rZ!J*k0wvxb(5rI9b=aSqMOXAaAg;ylU&UDb z4$G4Gy*+CbFx;Qjm))WMk`-pZQ0?0dEHz+LfQDR=0Ba-{Elt=yPphh2rAMGi-PSJ5 zcB}R6^4Yy=U%TPMzi+_YFqiGao{%>v|KL=!QS}7nyG}I|RUVYDIn@kQSx`2r()N9M z;|?{w{Z#(^PIaLDG_jPZ4QdgxAVT|8VTYb2f80q3mWX>6qSFeJ6rt}98fpbYs7YJg zsV4?3X^Fek?HxK@aW^&CRxppTIE{COJHo|1)Rk-VV5Wv-bFoaf1Uq4Da-1dZbwGqM zy?|%SW_7H?+2^)5%fC*Y@)WyKveCgjD1y|>h~?BC0Uj6TNsP=3=9uwlh5){X$w9U9*2ID{7^)}mEBN#m@b?Y9H+_ya%D(l9i;6I0bW6Gv+;1P4N~ zuobd`!C)tgm)mTVVG>CDir@u<+@k+yQ>O(@)BVyLbF@)in$yv*K?Q@|)mJ%io%PC} z+k<_jM&}N12kkw5!rI($?(T&^PZnumm%r1M4fHEMRPW|4VB6J|d4r%!%k!$(2kJy# zKYkZe#f2T?d_-bFA_0BLCVjD)Jay_+=8X}L&0ry<6=skQ5<%1>o>Ja{tcmp1M_4Hr z+CEOC0`o{~>{t&B0|S@7?hp4E%_-$01>beW-E z?$}ZF?HWRDaMzw{M7IKVSk3BIpmud_-~Uq@YX!w0oboeM_O%SsEtq0;@ufQ6H7Dm! zW=NVPTAmJrR7;)P)n*^7DP4P;1xEO8A~ZSF&)}CC6#wO{^T)R9wE^aU-N{*s`seao zb-ddUfGx7m1=yG!@%!o}vF4b%-;VS*Yryn^Gf+PlC*crcd$Do8`WSedU}A$hYF`N` z!^2(K7iv=fCO|0E`8RfXbytSef_iFLnIySnGGP3q0=VcQjc@)y7>R2_4*U8~h7 zmDwSuYy~l>m5tEVc38|+UGW#)wA#;uadx}eblIfJd*sAH=|;j4+CKt=v=rV6EM$Vm zBsWfGEgrqKVcMSEEG9j*;S@X`#v=x#;;|Wza7aGzE$o_n@;Y}i*nC==Yv*N=4q_mB z{4verh3fqt!_EeL(8k0+T86IWup$@^G2Xz#0V*HnVJLybVDY{h)w9PSLcmYJ2vvWq zkXdCO5^-u5Zo7yTGixYAyUhz(f|q#?t4Dhd$=tB3DPhs3*g-oWPN+Zk>>6)oWtL^9 z7@$NGfLfMm(*UVWkY65xaoi3Kv7Q2}?BEb<50!x-)^278(izANk|iVp9jLn0fw|o)6OmUWzcq<|B9+U#z)o z7D(V3y`a97ucRlyIf(HiSed7p=D`qbM?31^CF+TUMr`j^wK!=EjEhOvLCBYosxo3zJE5v8;Wt%WTugLK39w8Lfy zy1y~C5)Dn-wikgM{bY-k>gA%&9Zn^Q5C$_Zg0(M-22q&yOr$IP%c#DkA%`PaQ!G_? z^etdZ)$YEz_#;FNDE@<~VDZTQ6H zX?)_;o#Yb-*TE;)F?ejvCqg~fRx|r&$+u9#7RW|e5O~cLUQYk>P*{g1{AS0*-)RmzP0SjUYrE)reTB(2o@Hu6q3JK7%!G(i`T$PVNV>WY#rw&_+;8ImmrOv#*Oh zs!LjaRFYX$e?LW<|WtHh5_pcB_}q$&Q1IFb6nvQn=tne2cC~ zs`la$A6OXi6AoTG1-3krR_3wov@JMGF!74sH=5y^C<6K<9lf#jdrYqb8H}+tF!<26 zz~X=g!p?*S2O;j!;zS154QgEsHGbq>$mVL?fSLTW=188@=YQ$ZgI!Zi82reDu0U7* z_>31B=W6(XTqG?1KDIn930yroAYYXX>o&$gnzyiktdv1Dm~Vlz&>zUAd`{y9Nis8n z!B-gbI)?{%#^)|LSN(28R^0VH77Q7=cuk!Ju9B}b72DEY2^@A~(+Cr*HLsaiPV5rj zIJFhJ_N}g22{O#{!_??G;UNw6t?t`jQ2>mmom>S7}Jk8%QHozU^dn z#9vJd!CR#%3^=nVGLJJm+zL@%yO@%dMdjgPC}M zo+6ygi&$cw#ab#!L2Yc3c#vwkf=wffqr;fKNG`!3^+2GH!Y1QVzzZV2menARDYj4C zt*1j$#j*uM45Y(wmD#a~XN2ByCaErBk(AbTQcjqp!P+CPmIE-LeEqRy1f8n zBu7^uQz;}yR8g6ObK+XnU8tytm|H2MCyav`h2aCzU762Bfa3lw&2`0bLs*od>tZae;fPFOHwHgrZ z!);WhU9thhyrN=5wy~{h*w{g>%)@PChh%6+NlW+2$>l zW2M(aR@)O-Rd*b?o)!3c6N z$is-0)D!WGN2wHA5$PP{wf#mDB@3q@#VY=$RrGQ$R_h6HA?6sKj(}eSPfKchz@}bf zB?6dgOjW=R*l9u^?g2eu3?n?hx@ADuR@?RHfDT<;7eWSssB7a)VDCE=riPJ1!r``* zhfp9H?> zYcjzA`Qe=y7v?fwr>np?92t#WgYkKtm?5+4W%gVO$vl!@q`4{YzKdqTMTVIc2Tz8F zaSO@NziDt@nbVOl*D;00ln_Q7VFl-@sh4!TOyUqgsM+La#3L<_>ot!V+MDmj5~aMa zp|k)kH~^VQkGfGwIMWJZ;yv}r@Nw*ORdjCIa7VJqXMv+w-7yL+j(VlmEo>i&j&r6m zmB-ckbBFX?qWd8YTWm|LBpx96Y9(e`Y1CySyLA8JULXmFw%MRU_7)35g2iLHg>Dqi zJ#T)y!vutv>#hhq0P;+~Ja3dbJg_U={HcMh-8}R-{xS^@1Jdb>QoBtlDc89>uJ2{q zU?)R_fXgz5$OO}2Vpld&J&xC~WPx@WoX)d7pe*Re(T0BV>Bkmv*FPYm>=K6krxd0| zc?^NDSO*9seaTc2ruv~#v^8dVSV3BtV1^)aj?X%MF})U@*Dg$EHqVkG>0`lz_cW7J z{w?uA)PN2NoE+&Y239vr zkvn4a$JL%u!*O2!dQ@4&IV{+zTi|VzB7i|gy6BKGcJ$e}koei?ZUHw&JGxwL9(`7x zBR&RSY&tQ9egqO$$4BR~Mim@0mHkpxkI7*_sHI~@_HbisS1@(pl$1=ZBU{v$VXwzklkuOLcai~C?&;ucw zNy#Uz(UDp+b&<(hvxM;LEcQ|ZvLQ|s2z#}RT5@S}JZ9o4S9ml)X**jfKh{E$)wb2t zm<|`6gn$Y5JPLlK}MyTXF{pk@k6Fs}@xxen+JQs85Eg--yjVrZOJuBj(BW`ctDff<@5oI)m4`kv?Y_5iNo{MZ7ANflsI9@UX%cUmrhb#?j&&*pFY3UM;<>7gB&bE<2~l2pHmK zSaKviv?cdo3L=9ow4}}fY6yo^`sF44T}f?TM0ll|k&gF2V*~C~vo6o+>1}bP8Zohm z0An@n_!bk<;)r_U@?L?19!eh}YVoKKFVD+yuTRMIW1rw)#-^uGw@ROoU))Ug4N;3e z@##r1SEteJG&s`AVaS9879QM|kiDQ?gZwLUo z&}znQPcz+t%0s}(l3*>ODms%{HZJ6dc@*0A*Tz;(WPgmKptDvOCb!uFZ7DN1K z`!xZ5aKG*F2DrDz8qh7=0-Nqu9UQR_VgyTK50bVF=UTmoM_o~Ct5ip{QgPXxP8FKF zCItvlxG=@lFzPss4=$lZpyq=aBepmScF-HsK9*buUO9N=%3i10=B=>J1&D-CUfB`} zCo?=wOl(V67g_?2R*|sw4rIvB3$-@l>V=8D@{E2umKV5Lt~(bGsFM?O9h2p_DwE1_ zEcY1}QlH3vs#Bl7eyUTaU7XHcjBz*eZL*Z83gCs4ysF9!lSI*P5YV;ovZ~&bZo*Jt zY(kP(wJKZ2MYP^LOZE&id52El(9scAR-cyAnOH%)5P?=W*&8Odn|%>V4ZqrUwj$}5 zRQ1*Q8QWU}qG5UQFH*R_Z9>U1o9eiUBmiS=2*tJt{z1d!vbTN%Mf*7CNY~;NcsbBa zW|HJx&N(kH?1@tznl>2*#RTP4NhXq@y?v2ELeYb43_^#n55Pb*C6heKv$Ndnfb0$| z01;^i@q)HA-1Z^Sgy=;xCq<{3z&M9}l>2rE8vdE{W&~C;*=~|zbOL&vRzZgF4MzhG zTRKtYrHl^@0VQ}^C8|ulB~gW_tIRW1>SHZVEnGHPqqEXMizXjOT2hIr>iD2iyjTe) z_+u_y%@Mcarlz2U{lLTLnb7Ruvfq0sM|B-+tr21=j266(Bbb9yDtOf{KV z?zxvPIyBDjqNVjsF zFf_(-exhXs41u7P@++k3FsTRLgd03*Xu9hd=`wheS}>_&An6UCR~shf;UaS1q%Q2w z>Z3{H%iDUF;OV;Zj!so@daWy)vK8V^5+s8IazpZ%nlX7ub~4Bq8%asWUHRRhKFno* z)i^nSV#3q_0!+q<_aP&SIME?Vixg8bmjPKwCNt>SWHX>dZZ@MH0sudKgKgpZxX*Qy z*eB|a>qdf*H?JE8+Wk`|bvun5VowL11%l|}9!V{l(l73}eY5aZ32uqdo4`GgjK?CJ z-h!bZq=4gop3_?=+H29BIGu6>WGA2ldN7mLSgi)=#V#gbB56ahv$__82IEbzx)@-J zN2w=Fv_qII@zw&Q%&~3srh@B?A>vKsA#n+WUxFDhFBDKszvmGN5n|1h0|F1A1Wj;n zyJ^k_jP}Tri@S!qj2=SxpPZeF@>U`6>b~G-A$#!^mj{Fs< z5D%##(|Y=Jl1=PTGp4zxiI!8Ot7Ntle3E$Za@rgiLXkWy9oE8+@a?q2lH^F9%kP}t zP9{;w+|WimY;=T#)))enUYR@PwD8_Uz-D1u+VNKmYPsSbP>E9sd@*Q3ClgN+$d=6I zUT4Is<`@UG_o=0omz8SS5s%a0uva{2B+2&NIuYpp!~PJZvW8ha^Ob6o`aj#$krj@l6wg|F1wr=5_$}t zt*L4~bEBRarxVi|(WHANZ_(C)J@7?6CcNXLL}-YU|1K`qJG zuPpsqky<~yBa+ci&pyYubq`j>8^(W`eXg(3c`mK7*#>o0O(lP4N5j6FcAUMWetkpd z++>opJmSN#8Y;=p5BrflUH8%`4WezHy8S z)Ll~Q%%ry`F_YXQSa`-v=#QDHZ`Nq`Q1#NhTh#gW-SEEafY6A)^&yUgv)P8{;g*c0;0BAzMwpxg>rDBr*%Q4nqh= z5kGD3|ARmzAOvNI$qeIdso!sf{dR5~bhN3N8O9Jq55}zOvp)%~n^MuafPVA)mL!w( zIxB)Lr$dID4LL0j^FNx@?ccAoK$YCmua&;cxMe`Ue?Mch#<)!0MZP=CMk34z0RIC=)%QD}$}lRS`+f9Gv$>^Z%+cIX-42tVR{$bnbeKU1Dtm#{C@ zUAK0@Yv)^T9Wc^ejXV#+Q(T@QWpnzw>$nf?1n6*QKniHZ#2*L~X$8ObFt2)feEWuy z+iV8Fm)%Z)=iFYC`zMl79Te))#*ISnE%7VuzG)Ccm4Dm_GQD{ zi-KTX!$*r#7~g+CzKR-%uQ)m_9nViXm4*kGPWJi@=}l|YzwZ8=H?L8*E$gYovMw0g zf7wO+Fg1*4M;qQ)ww}l@#ciPVbK-cFn-C3clZaJ)YU5^RNT6<3l$Ho?2`S# zCQPAhs0`NIo^g5jK8M#!bRJw;#(%d-rL7u3L(g5+nTo4WJF;0VTeW4z+9!#BPa6K& z9=Rt)Zf(=#l?Umw9a$(hK1k(8F84n~4^MOPHzE#qBO#fas0DM%n#+H(uX#0`I!)@-n(O(C+f>y9 zm$C2E3lGePyEtd zo9(K4-O$`^1W9`Alq~EZbj8sl`NMYg^16J!Z=3pLT~6oE^(Zcm(-O2_xXDa#lH^K6#{f?lDud zy$)sw-Vl{~1t6Jd^emRY=< z>?2+iNm>{VkC^*duiW1fals&Yq*cah>eEfBSf;Ld?2@eg&jODAA`4pp%h0Tze=Og( zom$2H>OUXLDRxHS#s`*4@24?;_n9#S6UlE#EiSG~`F_>&@oQbEewZn3Z<^Jr$GeO- zP}kE80K)+>1Q%yEAI8sFCj>n3orVWl7$>$d3+ZX3%X->=_5I@$)7v1TCU3c!tx@l7 z8OPQ%M7BP{*aHnOKk+^l4{p1XrGI=Lj9?aU+Wtv|kl?srzSva(tM7=H+ZfO9oo9@z(=?BgRj_ zN9mTeRqfhYlyy8g-m=ordt80K^R9;ZyH;~`+a6!1I(!yiHDi8N%}l$ZX1JQfO9d&g@O{EGvJuqOU z`Gpn0QYC84)AKu2R@_igSyeyZo^w;Qc1HD_c~+xe9e;Wu8>Z@>xg=+Eny}ho@HCX2 zP~MD^p}a(W{7m;iGio+!$I=@7&vF(x6cAP_>K_GEhsOSCA-sJ=lOk$dV^LgnG&Qf^ zvWn4qZU6rLC!^eoQN*&_oc^Pz(-POBPK>KU=|wpkr9kQSyYm__z8Bg*LPT{u;B? z@fV+DgBl)s=~bRJ2xxRi>p1)s;BSzc^U9*a4V?)!%i4!tT40Dx|19eW>ba=j1BwVq zrSe`aVp#6g1r3K@?ZhJW*}@u#jzK8eEpo+(c+34{6{OQW*4_zaPt41x}UZp{<|Mj k=2q3vvYH|+_CEe-M+}7nng_7OYG(5VY=6U^=79IV0n6Iy761SM diff --git a/genesis/process/testdata/smartcontracts.json b/genesis/process/testdata/smartcontracts.json index d2b34368fc..9c29949deb 100644 --- a/genesis/process/testdata/smartcontracts.json +++ b/genesis/process/testdata/smartcontracts.json @@ -11,6 +11,7 @@ "filename": "testdata/delegation.wasm", "vm-type": "0500", "init-parameters": "0BB8@%auction_sc_address%@0A61D0", - "type": "delegation" + "type": "delegation", + "version": "0.*.0" } ] diff --git a/integrationTests/multiShard/smartContract/scCallingSC_test.go b/integrationTests/multiShard/smartContract/scCallingSC_test.go index 0bf9f0b9ac..acd55eb1b4 100644 --- a/integrationTests/multiShard/smartContract/scCallingSC_test.go +++ b/integrationTests/multiShard/smartContract/scCallingSC_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + logger "github.com/ElrondNetwork/elrond-go-logger" "github.com/ElrondNetwork/elrond-go/core" "github.com/ElrondNetwork/elrond-go/data/state" "github.com/ElrondNetwork/elrond-go/data/transaction" @@ -24,6 +25,8 @@ import ( "github.com/stretchr/testify/require" ) +var log = logger.GetOrCreate("integrationtests/multishard/smartcontract") + func TestSCCallingIntraShard(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") @@ -580,6 +583,18 @@ func TestSCCallingInCrossShardDelegation(t *testing.T) { nonce, round = integrationTests.WaitOperationToBeDone(t, nodes, 1, nonce, round, idxProposers) + // check that the version is the expected one + scQueryVersion := &process.SCQuery{ + ScAddress: delegateSCAddress, + FuncName: "version", + Arguments: [][]byte{}, + } + vmOutputVersion, _ := shardNode.SCQueryService.ExecuteQuery(scQueryVersion) + assert.NotNil(t, vmOutputVersion) + assert.Equal(t, len(vmOutputVersion.ReturnData), 1) + assert.True(t, bytes.Equal([]byte("0.2.0"), vmOutputVersion.ReturnData[0])) + log.Info("SC deployed", "version", string(vmOutputVersion.ReturnData[0])) + // set number of nodes setNrNodesTxData := "setNrNodes@1" integrationTests.CreateAndSendTransaction(shardNode, big.NewInt(0), delegateSCAddress, setNrNodesTxData) diff --git a/scripts/testnet/include/config.sh b/scripts/testnet/include/config.sh index d2d7adbad9..e5b31592c9 100644 --- a/scripts/testnet/include/config.sh +++ b/scripts/testnet/include/config.sh @@ -21,8 +21,7 @@ copyConfig() { cp ./filegen/genesis.json ./node/config cp ./filegen/nodesSetup.json ./node/config - cp ./filegen/validatorKey.pem ./node/config - cp ./filegen/walletKey.pem ./node/config + cp ./filegen/*.pem ./node/config #there might be more .pem files there cp ./filegen/genesisSmartContracts.json ./node/config echo "Configuration files copied from the configuration generator to the working directories of the executables." popd From 51f01c3dc8a37d3ccfed40a2191e7ad2749c8d54 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 15:59:56 +0300 Subject: [PATCH 68/79] adapted the new delegation SC --- .../config/genesisContracts/delegation.wasm | Bin 52245 -> 52411 bytes .../versionComparator.go | 2 +- .../versionComparator_test.go | 2 +- genesis/process/genesisBlockCreator_test.go | 6 +++--- .../process/intermediate/deployProcessor.go | 14 +++++++++++--- genesis/process/testdata/delegation.wasm | Bin genesis/process/testdata/smartcontracts.json | 2 +- 7 files changed, 17 insertions(+), 9 deletions(-) rename core/{version => versioning}/versionComparator.go (99%) rename core/{version => versioning}/versionComparator_test.go (99%) mode change 100644 => 100755 genesis/process/testdata/delegation.wasm diff --git a/cmd/node/config/genesisContracts/delegation.wasm b/cmd/node/config/genesisContracts/delegation.wasm index 51a41a0896eca8f95a086c1198c6d373750d15fd..5bfed3fe06463ab3250308232c6a47fc098e2604 100755 GIT binary patch delta 17039 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 delta 17475 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 diff --git a/core/version/versionComparator.go b/core/versioning/versionComparator.go similarity index 99% rename from core/version/versionComparator.go rename to core/versioning/versionComparator.go index 58be5b039e..181919be80 100644 --- a/core/version/versionComparator.go +++ b/core/versioning/versionComparator.go @@ -1,4 +1,4 @@ -package version +package versioning import ( "fmt" diff --git a/core/version/versionComparator_test.go b/core/versioning/versionComparator_test.go similarity index 99% rename from core/version/versionComparator_test.go rename to core/versioning/versionComparator_test.go index f113cca1aa..ea699452d3 100644 --- a/core/version/versionComparator_test.go +++ b/core/versioning/versionComparator_test.go @@ -1,4 +1,4 @@ -package version +package versioning import ( "errors" diff --git a/genesis/process/genesisBlockCreator_test.go b/genesis/process/genesisBlockCreator_test.go index 944ab6371e..3a7aeb0a76 100644 --- a/genesis/process/genesisBlockCreator_test.go +++ b/genesis/process/genesisBlockCreator_test.go @@ -127,17 +127,17 @@ func createMockArgument(t *testing.T) ArgsGenesisBlockCreator { 0: { &mock.GenesisNodeInfoHandlerMock{ AddressBytesValue: scAddressBytes, - PubKeyBytesValue: bytes.Repeat([]byte{1}, 128), + PubKeyBytesValue: bytes.Repeat([]byte{1}, 96), }, &mock.GenesisNodeInfoHandlerMock{ AddressBytesValue: stakedAddr, - PubKeyBytesValue: bytes.Repeat([]byte{2}, 128), + PubKeyBytesValue: bytes.Repeat([]byte{2}, 96), }, }, 1: { &mock.GenesisNodeInfoHandlerMock{ AddressBytesValue: scAddressBytes, - PubKeyBytesValue: bytes.Repeat([]byte{3}, 128), + PubKeyBytesValue: bytes.Repeat([]byte{3}, 96), }, }, }, make(map[uint32][]sharding.GenesisNodeInfoHandler) diff --git a/genesis/process/intermediate/deployProcessor.go b/genesis/process/intermediate/deployProcessor.go index edb1d79181..2f63ffcd98 100644 --- a/genesis/process/intermediate/deployProcessor.go +++ b/genesis/process/intermediate/deployProcessor.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/ElrondNetwork/elrond-go/core/check" - "github.com/ElrondNetwork/elrond-go/core/version" + "github.com/ElrondNetwork/elrond-go/core/versioning" "github.com/ElrondNetwork/elrond-go/data/state" "github.com/ElrondNetwork/elrond-go/genesis" "github.com/ElrondNetwork/elrond-go/node/external" @@ -163,7 +163,7 @@ func (dp *deployProcessor) checkVersion(sc genesis.InitialSmartContractHandler, return nil } - vc, err := version.NewVersionComparator(sc.GetVersion()) + vc, err := versioning.NewVersionComparator(sc.GetVersion()) if err != nil { return err } @@ -182,7 +182,15 @@ func (dp *deployProcessor) checkVersion(sc genesis.InitialSmartContractHandler, return genesis.ErrGetVersionFromSC } - return vc.Check(string(vmOutputVersion.ReturnData[0])) + version := string(vmOutputVersion.ReturnData[0]) + + log.Debug("SC version", + "SC address", sc.Address(), + "SC owner", sc.GetOwner(), + "version", version, + ) + + return vc.Check(version) } // IsInterfaceNil returns if underlying object is true diff --git a/genesis/process/testdata/delegation.wasm b/genesis/process/testdata/delegation.wasm old mode 100644 new mode 100755 diff --git a/genesis/process/testdata/smartcontracts.json b/genesis/process/testdata/smartcontracts.json index 9c29949deb..18057e6099 100644 --- a/genesis/process/testdata/smartcontracts.json +++ b/genesis/process/testdata/smartcontracts.json @@ -12,6 +12,6 @@ "vm-type": "0500", "init-parameters": "0BB8@%auction_sc_address%@0A61D0", "type": "delegation", - "version": "0.*.0" + "version": "0.2.*" } ] From e4ada6e35fafc8aec073938dd0eaed13a417bec7 Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 16:09:59 +0300 Subject: [PATCH 69/79] try catch the bug --- integrationTests/testProcessorNode.go | 2 +- integrationTests/testProcessorNodeWithMultisigner.go | 2 +- integrationTests/vm/systemVM/stakingSC_test.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 101a853024..0b11dbd192 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -1423,7 +1423,7 @@ func (tpn *TestProcessorNode) LoadTxSignSkBytes(skBytes []byte) { // ProposeBlock proposes a new block func (tpn *TestProcessorNode) ProposeBlock(round uint64, nonce uint64) (data.BodyHandler, data.HeaderHandler, [][]byte) { startTime := time.Now() - maxTime := time.Second * 20000 + maxTime := time.Second * 2 haveTime := func() bool { elapsedTime := time.Since(startTime) diff --git a/integrationTests/testProcessorNodeWithMultisigner.go b/integrationTests/testProcessorNodeWithMultisigner.go index 3b15c5e0ee..2153e9dfdb 100644 --- a/integrationTests/testProcessorNodeWithMultisigner.go +++ b/integrationTests/testProcessorNodeWithMultisigner.go @@ -269,7 +269,7 @@ func CreateNodeWithBLSAndTxKeys( twa.Address = twa.PkTxSignBytes tpn.OwnAccount = twa - tpn.EpochStartNotifier = &mock.EpochStartNotifierStub{} + tpn.EpochStartNotifier = epochStartSubscriber tpn.initDataPools() tpn.initTestNode() diff --git a/integrationTests/vm/systemVM/stakingSC_test.go b/integrationTests/vm/systemVM/stakingSC_test.go index 94d8630283..549f6507c3 100644 --- a/integrationTests/vm/systemVM/stakingSC_test.go +++ b/integrationTests/vm/systemVM/stakingSC_test.go @@ -335,7 +335,7 @@ func getNodeIndex(nodeList []*integrationTests.TestProcessorNode, node *integrat } func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9999961980) + expectedValue := big.NewInt(0).SetUint64(9999963900) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) @@ -350,7 +350,7 @@ func verifyUnbound(t *testing.T, nodes []*integrationTests.TestProcessorNode) { } func checkAccountsAfterStaking(t *testing.T, nodes []*integrationTests.TestProcessorNode) { - expectedValue := big.NewInt(0).SetUint64(9499987270) + expectedValue := big.NewInt(0).SetUint64(9499987910) for _, node := range nodes { accShardId := node.ShardCoordinator.ComputeId(node.OwnAccount.Address) From ae4a880c60124baffc97cb2504196f9938044fba Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 16:13:43 +0300 Subject: [PATCH 70/79] updated config files so the node will start --- cmd/node/config/genesis.json | 1316 +++++++++++++++++++- cmd/node/config/genesisSmartContracts.json | 11 +- cmd/node/config/nodesSetup.json | 520 +++++++- 3 files changed, 1758 insertions(+), 89 deletions(-) diff --git a/cmd/node/config/genesis.json b/cmd/node/config/genesis.json index b17f9b7f74..4efa6f6d42 100644 --- a/cmd/node/config/genesis.json +++ b/cmd/node/config/genesis.json @@ -1,98 +1,1298 @@ [ { - "address": "erd1m87mx5x20lkmj3tcskv0yw0vc2m8d40mnlfyvep4lcqkyvnvlussjdkulc", - "supply": "1666791666666666666666666674", - "balance": "1666291666666666666666666674", - "stakingvalue": "500000000000000000000000", + "address": "erd1gsu3v056q4ka9mtfrxw3nnx7wnsgk4tsjrulveuz47hf9hpgwafsyyk7jf", + "supply": "151628787878787878787878903", + "balance": "149128787878787878787878903", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1heea59kkdmuq37ghtu39gp22fh84vy0vlshd6dkmf04a4ushettqy4uhwd", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1tjtt3m0huh5a9jkmhhpu9hwh7ls9pccd2xhyv6s0s9t6r2m5s0cqvlwysa", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1rhxtkf438tazahc4tkmhv6tx6xejacqcyl9sfjh7de9teh8gjh4sqs5cl3", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd17xzxe9lhyd8crn4tsdarw23c7dptu498p3vajcv65hzw79mth29q47chvn", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1hyuyaw87k9c8nh48lxmhlgpzyph7asc8gtf2zusa4hcd6hsxzl0qrkxlw6", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1qwvs9rr2h9epd7h3ft8wd556qfgqw9tzswrh8ev6enty5cd2tggs29wugu", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd123djyzelgvkw2jtk9m6jpqpm0xzlc6fcl89lctwgdgrw33terdaqjt7tqq", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1h0dyclgzu9d0086sqn25chncq4lxrznrt4kkeyc3qvc26t6e0jqsf2cze5", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1e828y6e0c88xql7x7vzysy505znea24k8ym8ltwgh6t2k9uj00zsk5vynm", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10r8gz93suswmekrw92nht0xvu6rsqsurhyfrhypp5apj7fltq4aqjredfm", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1zxw8p8qy2xpqm0yr2t77dmfk479j4xra0nkar0w2tx7ru2uj4zkq6ztx5d", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1c6n4tcxng5d8glhpd70yu972f25na7s50nvjz8w9md28nx6ehvdspwdejr", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1vdn26mcwx85j2se2ugu7k5zqnm08wpe5wjgh4kn8e5mle4samzpsfutxva", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1aewp0su49yp4z4z5xfy5dm82v88h09dh9my0m6u5fs5na6jmkxsqc7f76s", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1tqyerea7lxmdllu3v7k5vhexcyv8wumf8fykgxae64z9fea7kpaq3rttd7", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1stmgjznrwrrc5pgetm7g56d452dwhrf9uxvs9vd775ptscm26m2q4n6smz", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd18mnvj42ukmhzz9c8r6l8zkd0y8uwt8l5qzmskxp79lvvk8hzs5tsqcuhe5", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1a4jqqqckp8kyktnrr8682rppsuryxnlyw502nj7pa3c6aedkeq8spr9knt", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1jz33au4lu5eyv6cx70rzs60jnqh62g559utv00z4q72z6ryll6mqeh2a6j", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1k6xe5rgxlaxvmpj0fs00vw22rqtv2z6d69x0et7ljeef3uatm42sr64g9w", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1q9d8u5ka5jsz93qwd2cnj6sz9w9k68uehhph4r2qfsqhxq9nsflsf0hajy", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd14940v2285g4ff3uqlsp86pehva8n3nna0u9t3f0umjf4hxqlqwrsuvg0kf", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10yvczhthh85k35lrsm74fcpegztpwnkyprz0jldt8wfavc27wqyq64ap8l", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1fg0yjdvh0ejeq79avuygrstghgz2guldg2z7hm98es0l7qgls42s29ycs7", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1f42duudjaehtz9fuunzht277y2859nwagvph58y0ksnnt2af4kqsupn0c3", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd170eld09x604gsfduuke2ew20fzq8ujwp4w2zeldytx88aw63fg7q8w3gyz", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1az84ef3mafn6uplkqhew2hn5cly9ng6lkphmntk9rf5298p3q5xq98ny8g", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1gsvpwqdq265udqzqr7aacyr5fv2789k24x7t9ugc06g7fvsfnpxsvu3qyf", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd18s6krt2wnzsu78jkdr8gky4fqzkltg5324vl2su2tv64x5cj8jtquv4y56", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd15x2r38terhqn4m98a7zdglnr68dz8cg6tju0d4rtu437glyznrqs8pkjh9", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1jrpykk3hvryycwcq03k5rdupu94d8pprr78dfpyvkphtfzveka9s9ut53q", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1d9sweja7lmcpfqsm0020u4ww3t4p0c6sfg8uc88jala6x3vqclpsg359mx", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1nk2sl0tcycspe5gn2khh4lxjx5j0lj2j03ejmqkpuyjz5pq88gas2l7mam", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd183wvn5aszcjge0fra8t96zr6r6u0dpcduanerqsmwn590gjg7ccq6yk82y", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1cn59rh2zfk8emumu3r94may7ttl43qrw9s4psvg2evwl6x0c46ksy4ya43", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1h7prds3ta3hj3l6a06qcq2djn56hnvsszne6pq2mgq9j0cfpyuesz29nh9", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd17vun3k0n7s62lzuls98f450qvymrv0sxllvw07z7hgtusf84sn3qjwmnp0", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1dv40ser2f06sfg567rppyr34uh092agncvtcx46wdczftcvkgqzsm9rk2l", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1amqdj3y5rshq4haxqagr9pd533tefx8l7mtmvcs324c4xges5q6swv0258", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1cnvc8nm0mgasu7mgmxlgryj2z54eke8vdt7ap24qdxxp4q4mjgjq8vlna2", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1rqr5lteu45ll6vavt99m2raxsvqayy4wrj86nj0pznf2elqwwngsg05vul", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1d570ntyctu8s50azm20u6qxcpgt2uxnxygshnxqtwwm276ac2j3sma26xy", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1yxv3g4wgnen6a5w8c2em77g4d49q8v9hsu9se34002hyma4xh8usczs7v5", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10k2dpqmjfpv0gsehkjw87t98nythfkaxvljg53d52unxc03dw7pqp3zrd0", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1j0lwme70yd50ue37786rrq5pe2w76qdpfdt0h75gcqjkdtxqx4zspuua9c", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd12mc66p7gtvj8jdcrv38rlyphdl6xruy7d2qmfyws4x7v0ugrj5eqy0274c", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd16r0c84zuklwkrjv8xrp39aqc8m7zve2dalqxekcr48ea2p5vydxq5jk9ez", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1d97yyspmn9tuda68dt7aq8ymjpqnyytpgahtw0k0z4l0pk6mwlqq3gsm62", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1mkrqlzf5upejs4fu9c05hr0zkrnafnl6f0hytyd5q9l3pvyftr2sjx5xmv", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1lp7h77qzg3xle55y4q4wqkjga3u9dffz62utl5hgk4yjl7qdwdvqpljq2p", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd18epr37af3hjgym2rjz7hkwhy943yh2fc8zc8a28l3z98jq3c8fsqsar5vr", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1sdcks3rdmzqf4wewvd7ay3zp7uqhf0n0qpwjuc9efdu7zcl7z5sqfp5st9", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1fw2nra2t2vw4j2t0mwh92ytfmc7hq7fhkcznjt8ppqeq80z823rs97wpuu", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1e70garz38ew38jvt6a4a6yz0xwvtwcax952n00fxwtd377cnn5cqnsl0dt", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd148zgfnupmra5cgmujkah5d88e2y3z9vmmvec8jldzeq85xvt9msqzxlr02", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd17zuwcwhj67mvjg2hu6nexyr8nrtrxqtpkyh3k98ndk4n0hj9g9zs30u6kf", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1hjs0qfpz7zcegggdv29z0c8lk884580q2s0eaymhhpne5tqzdnpqd2gprj", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd14h0wafvm3pdrgm6zdn5ru5xz2ng2hs6ng35ar6kst89mamamutjsp8c6fs", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd15zrr7y0dydx7pqk4cn5h33snwqkh24jh28wel60x3ekdfp364vks05ctkq", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd12gkhmh30967tlxgk0ec7a2q5nv0exlv2kkdx4gdy2l7lw2fhx76sa9pqge", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1hgc79534rgv4cemsfzajtzy7varsy9k6wxxenj874mxxrk3zg6eqhs9e8c", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1vcq7ee8qq4wa8qvh3wcps5nccnh657uhf67r46l7dws6y63l3das7xecr4", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1kyw0yfe6hr6hf4vj3ud3kvx587xhy2ccxmcswgwvj4dam3vg76vqf7quc0", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1zajxa70mw8lgqzw72g93wtrlcc6skaf4fasx525az0l3gdlhv2rqyd547e", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1nhjkwwrlek7nwkw0p795gkp972u3ncmwk82qz34hl3hvkcuy9a7qs4zf4j", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1ajmkqqsp07wttwftul2jt28d4nyrev8mx0c2v0yyytmukc5t6jdqrgt8fg", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1m2g960p38y8fwg209plnre0ethywgr98jsmca2tfcs4mpewxdn4qg2zfa0", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10htmaddnqctk7egxrf0uqhqx307s0eehmnslnvvpj5d3ya4mt0vqzxsu88", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1z9qhml7esa30s5cjjgkd449smwmcv009mhq3zdednm5qvxqz7hkq8ef72p", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1r6mf6tjaxfvu2zjrlsxdqucumjs5d42ekp54rsgv359m6s9j2efsrzf5qc", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1ydqnv9mq94drcwgy80a6jpm0c2jthekfqpt402vh88wv35qhsrysy8jv0h", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1z37rknaqptaecvqrnu6ntzpwwukz4fgeer4kwdhyuxyy7ttrjkpsagq3kh", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1tr2ramkhygez4fhmz05z0dmnvzh9suwnjmfts26dv9qjh5pclu5qpuh2nh", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd1rfyjyuxl25rsp3q8j6r6y2z5tdzauu463dzdtl2293fj5yc842ssx7pdam", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1d3qgl6xwmg5v9geup7ceejgclzpwqmflgqfl4229rnmcwl95dppselp75n", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd18cux4ftul77k478chttklwa94q8g205ftefam8g9z0ds253mwm8qw54xn3", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1gkfd8ksurrukf24s2vgvkpzhwwe9qx4cmxqd79zzp6rg8n43aq8s44usnx", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd1r6m0x3p5lf635g8ce3nhh0mhzv4ufsctarm2uamexxplzf3t5t2q05aqzk", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1fmvdaksjp3qz7l7cts8u0d08mrwqtxwer55nt0kwcz3jxrngvals6emq2z", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd1u6fw4egq8pv8ufpk5g3nguyf42hnfknq7w7rfhvrta6p5dss5zdsmn69sz", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1hh8u7kqkljugjxu64a4u5tx7pwqy8570jkd5qedt4hsh8kcq2ruqaffy43", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1zkl7qmvpr5gp3052zxks9p7n82ethxshh768vhr3z6kcnz8v3xesp392g3", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd1sw93x2nrtsnsa0n3vukjke2vaknwvyyp5e0gsfe5swwxnpf9dxrs6ek2xz", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1wkv8sard7n5d28sz9838ahjesec4zshvpeeyttjduvhf7t87wl6slqqxql", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { - "address": "", - "value": "0" + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1p4jdm03308hyq9fnkpwcqr2l4srn3ph4lvf6lqxnyeq9y8wuqytsxc9v0y", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1h8l7ygdawwlflee7jejxlghpargztyxxx5d956g9vrtaekt4r05qvuafrn", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1wqlw29a2p4mt50zrhlkzsckg5d04qynt2eautaxwt3hxdz45ck7q7znmec", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1qadvfc9lq69js0h70pl5ykcr8lgnanax00juzrw93ywmpxrkvdgqcfwpaw", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd15tfhadl5tjvqen360pkcsv6tq3c0k9p4l58l4adnqht640h636pqvese0h", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1v2sjdna47sp9v7jas6zscq9yf2s0jm39p9m6mcwjaaq7rv3ml4rq4tcal8", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1395trv3gshjn82qsmm3heqh9mgpgfpkursgnpj925ukc52637zuqsnrmlt", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd127cpchua3a4nqgmd7c977nclh8ch7tqxfx4trrlcnzf3kpvxku2spm2k0u", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1asd4mxzm2r8dsjd2m9esgexsqg4su9223pv6nzx47zm66vd45e8se8zpx0", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1xys528vr63wm6dflpmcr0xjwzkwpqlevg68g8g8ruvh0ydfz7lpq74wv57", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1vag4y8kza563q7csfkvfkvt05n2rpt3lhmzqasfleg04l8nkddmsn0yec6", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1dx3308wg2ar2x4jjhak9tr92zy39pcs80ddqke85yege5h2qrvgs78eeg7", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1dlyjs2c806n6axvmsl8rh3r92ku2fj5k74et2ycduhs2fytyhp6s7l86w8", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1mj7z70ugjcuyhl6kx9gtvn4fcdp40eep5thzknqrp6my0c5vdynshtggsk", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1cd9ktvc6a906796kgkj53xpxm32qgtrj6grtmpv82vz7jq08qc4sdj8xa3", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1eep60955eqfmjylysztvcj2cenkey8xjlarlvp48hv8ke33gtaqqgn2mny", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1ju99yygnuwt2qcc9lqule4uyw928f5pk87s3re0nsrx2zgeukskq0ydx6s", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd17v0ejzf67tdumctz8gu5ynq9v85leac9fy9u3xu83m3l5u7etwxqsrl5q9", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd122kkggpzc4s2a78w9p3m34uw0sfamwdnecunt2tdqc7cwchfmcwqcur50x", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1ze20hfejrjf0unzqckt2d92u0mvs77nf8nwtlq2jv6cdeg32j0psewggnt", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd13dej7tajx3ptchlhd6z76qsks3fdk2pu4ya0e75p0lhr6dkp8xjqhgp8wp", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" } }, { - "address": "erd1fh8xt5gw9rvextpdrkwrmwatszyl7sld4mcj0cy6nsmhxs8mpldqmwp4vz", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1w6yr6ty2s9wr9qdkrqfc3zh43dgafx42mxdwxng09d0mpdzs634qfevr8z", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1mjft95qcte0w9dp900zst2nnm50kwat5jqvs9vav8jskq5m6tu0q45s5r4", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd15zey3pusy60rhswasja5m7e6f2aefcggkqtwt3l0quurd9xt38cslplk8x", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd12k3qawnpasjl8hk93ggpl8x6ahuvz3w3fepwmuwwexeqzyjynx4su3secy", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd13krturgf3z33mc7vyzn8mjndx48ea3jwhwnsaa83tg06vqgmzsaqqq02zl", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10yrua0n8xwc38ftuwv4dzeset2t9h9hff84ntjedcee4j5usuynqfemsht", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1fnshkk5jdsqwk9yyrn0qeflmheaqk94ranlm5325tezk6swd2r0s2zje25", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd12dtz5uvl6c730glrcq836znrnw9g6jnz5d9ucxr5ztte8q0k6pgq8l3h0j", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1tczqagllxj9aa5pqnzsspqzqqzdyputhd53lpxupejhqaa3549qszngftu", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd13mzzdx7waqph0s5plgg66swl8aajcc58jup5vkdsyhver8mgrn0sp93h4u", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1acngdcqmum329msan3va66cecuy2jsejs39hwdkeewe7gaqduhzs040gsk", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1hdwhn7s4fv0u3mhs9ugtpxgt5wqxk96dtnlfg7dsw4mwfdl2zv4seanymz", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd10ycrvf9ju848vywxzdp4cf7vgc6ytvswpkne895kqec0jnxf9wfq2m9vey", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1pelp27gz67l4z5f07fnkys429pehdesdwaczutyvrzzayvdxecwsrqcp2q", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1lj58ggpefjap8w3z05x5cj8qetrcvcvv7eyacckmfzqehc2tgv5s2435lx", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd129c6yrww92q99d5353kzrrhyevgaaw6k6trsyn88202k745t9ugszvujz3", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1pr8vz9gxuztxem6c0u9fe23lhlq4nxmqy7namp0fw3curdkdmquqaavgjz", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd19dvr8d36ptqy5j5wrr3nevnsnamxj9fnwq0x3juvuv2mtcpampgqm90l5x", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1t9exuhvlqu9m2f85lw0q7gzgwk737ld7ykzrnvnpy4qz0ptm5qzqsd7zh8", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1dsx7473auedse5ksj7j8s8afvah00hcfwnfqcn648wv3jl3eq9gslv6k5z", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1zgc2zj7nyf4pq67nvqamw4dfs6mun0dh8umc4wx993u79zfftawq0ft85k", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1pz7rk9gr33d68ys750hw6n020v3xlzqn760uly5td36g6ydf34msrct7nt", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1fyxsl0vqkjy6yf07htuqxachjmcswcakzc3me9qd9n2tkx53gzfqzza48s", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1wy4h3f8fcna4gsgznmwkaqpfw24kwmcxkyat0mkxvsy37hmqru2quk0ka9", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd14rxsjjqt9q7wvhe7fqdgaak99gmlfn7fky70kmt8x4mc2rqal4dqlcnymh", + "supply": "151628787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", + "delegation": { + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "value": "2500000000000000000000000" + } + }, + { + "address": "erd1773jwmsaa0280jhn42j853a6964z324m84e23avjvf7qr2smju8sxhq9vg", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { "address": "", "value": "0" } }, { - "address": "erd1jmufwnqe06dvdvy5mse79k04qvm3h9yllhup884udknd4u9l0feq5xqatx", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1xrnjayplepxtayur6acfadeevjl733ml3wxqthqw2kuw3c6l7nasqk646y", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { "address": "", "value": "0" } }, { - "address": "erd16h4f6u5n346kfp77k6lhnxu27c3y4sc0urwcye3q6kjgus28ywpqyfnuh8", - "supply": "1666791666666666666666666666", - "balance": "1666291666666666666666666666", - "stakingvalue": "500000000000000000000000", + "address": "erd1dq0k7v6p482d0v0rq8p4x9hwmerkfjvx8fgkqepzvk09ez2vr7hqu9d0vu", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", + "stakingvalue": "0", "delegation": { "address": "", "value": "0" } }, { - "address": "erd15khnvy0vpcfdvxd000622a3es0muct9jh9wm7klsm8nrwn3tzneqqnjhae", - "supply": "1666291666666666666666666666", - "balance": "1666291666666666666666666666", + "address": "erd1q9gmv9r8wuukpnnp5r9rdzuc6nw4eh0xnfea408v00wf54q2ecqqmes8un", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", "stakingvalue": "0", "delegation": { "address": "", @@ -100,9 +1300,9 @@ } }, { - "address": "erd183nlfwerse0nljvvlvu4d7r6d04p9hd40h5u0hxkkf378y66e3gqhw0n85", - "supply": "1666291666666666666666666666", - "balance": "1666291666666666666666666666", + "address": "erd1x5cfqxpz8lk2njf0qty5hntr2ltdd5xgywsvyk7dzvyuu8z99s5q20gvx6", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", "stakingvalue": "0", "delegation": { "address": "", @@ -110,13 +1310,13 @@ } }, { - "address": "erd1pajyy0hn3kw5s9dn5pf8980fdy2d0evklrj03699uxtl4k0fyudqrzxf8j", - "supply": "1666291666666666666666666666", - "balance": "1666291666666666666666666666", + "address": "erd19y0l7v6j4x0hafqjdcyn6lkkgckv7w24zq6vl9ekyzruq0sqt0nqyd99ta", + "supply": "149128787878787878787878787", + "balance": "149128787878787878787878787", "stakingvalue": "0", "delegation": { "address": "", "value": "0" } } -] +] \ No newline at end of file diff --git a/cmd/node/config/genesisSmartContracts.json b/cmd/node/config/genesisSmartContracts.json index 8925746ff8..e4175016b6 100644 --- a/cmd/node/config/genesisSmartContracts.json +++ b/cmd/node/config/genesisSmartContracts.json @@ -1,9 +1,10 @@ [ { - "owner": "erd1pajyy0hn3kw5s9dn5pf8980fdy2d0evklrj03699uxtl4k0fyudqrzxf8j", - "filename": "./config/genesisContracts/answer.wasm", + "owner": "erd1098wtt750w65caywv6v5wyxqdpzgp78axz2j3lpxeq6e9c9uwlys28eh6v", + "filename": "./config/genesisContracts/delegation.wasm", "vm-type": "0500", - "init-parameters": "", - "type": "test" + "init-parameters": "0BB8@%auction_sc_address%@0A61D0", + "type": "delegation", + "version": "0.2.*" } -] +] \ No newline at end of file diff --git a/cmd/node/config/nodesSetup.json b/cmd/node/config/nodesSetup.json index e9daa2bf68..17fe6e1039 100644 --- a/cmd/node/config/nodesSetup.json +++ b/cmd/node/config/nodesSetup.json @@ -1,49 +1,517 @@ { "startTime": 0, - "roundDuration": 6000, - "consensusGroupSize": 3, - "minNodesPerShard": 3, - "metaChainConsensusGroupSize": 3, - "metaChainMinNodes": 3, - "hysteresis": 0.2, + "roundDuration": 4000, + "consensusGroupSize": 15, + "minNodesPerShard": 21, + "chainID": "testnet", + "metaChainConsensusGroupSize": 15, + "metaChainMinNodes": 21, + "hysteresis": 0, "adaptivity": false, - "chainID": "undefined", "initialNodes": [ { - "pubkey": "d5f3a29643ad04cf80645f95070cfc212f023e1088e3b5afc7de8085797a52ad13d46e6ea1f8b4c229e384b7a9e1fd183e3e4d5acdcc6db213e6237ef50d29e6fe1862b91cafb5137c8989982ced6cc84740e03b2d5a14568835663507364394", - "address": "erd1m87mx5x20lkmj3tcskv0yw0vc2m8d40mnlfyvep4lcqkyvnvlussjdkulc" + "pubkey": "32dbd94897d1abc7a25bf8eae279514d93cec578434146c59dd2b123d8a2e6258417fc7d3c2f40fa3a9d7c8a18c3951959b978a08433219554a5d9148a59e10074334214f578a79d246c114b64c13efbe294366d0e6eb9a864b7138a9089ee99", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "a4358d8219476921fc952eb6ae1b4e10d4783751abf0f4ae0d85612ed9b23938769e14691afa0573bd203b71ad08eb014ac31392bf67c89853f4b2406cccf3010624aeeb7f25e4df6a13ed724ef9c5087e8817e0323bbfb2fa7113dfdbc6f390", - "address": "erd1rfyjyuxl25rsp3q8j6r6y2z5tdzauu463dzdtl2293fj5yc842ssx7pdam" + "pubkey": "2766b8edd0c857f45ec2a44986be7bf3141ba2c29e37d69d924508fc628a37f8a565f2ee135624b3a6d60ba8edbbbe1618c3aadacd4b2605094874a38da630d397227aa23a3824c590b33a14bf2747c0f0fb8f9f8f23903a26997e3e258cad05", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "5b460b8d018ddc51854632d6217f855df162cda320f4e19f6e1d80425fb123b53c324ef5765e9ea7ce017628b85a8c16e85355ab72c0718ba260f14635ed108ed06948db50a7cd852f85ecafcd6aa93cd3297c31924bbe03dd1e36eafd5b1412", - "address": "erd18cux4ftul77k478chttklwa94q8g205ftefam8g9z0ds253mwm8qw54xn3" + "pubkey": "0a46a9a6476710e0c3cfcc35aea3806b4b8640f889a1a1eafb402fd32f7d56c37ac71d73075c0d8e968b3d5adc1cb906c7f5b8b318280182215de268afc2a4c4ef5b1a4db1685c2d214436edcf32e4ab062a0e14af9771936b86fc19e1afac09", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "7f4c290290fb5e1fb523fd0fdc480c687f4bc8e7637b1b0d23625c58a993566ed9211bd00095b316e67d2efb5e5dcf15ce602fed89267d1f8631558dfd679e64a4feac09ccd86f55a84a6c6e47c87037da311a654c1b6303bdbb2cf27aba1416", - "address": "erd1r6m0x3p5lf635g8ce3nhh0mhzv4ufsctarm2uamexxplzf3t5t2q05aqzk" + "pubkey": "4517a20b3c5f28acbdd7e4f856cda980d8e44a7bc96b48d727b45fc9bde7d16f759342503f4e1c872319969076d3a203597268f65d220d8ebf880a181a051ba7a483805d5cafb6d3191b8581da065bf99770f3d481e16179f7c7c1c5f5f2d113", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "be3125478c06d8ad303e1c08ffb1a7643de44c15c613888f09319658c9027536b5524d75d37f8551e24b4eb0b6583b0bc85b28ed500627a01a2fae6a95a6e888952633025d6b6770b30355d4deffd13e62e44ca91d2dd1efeb7a6e11eb5cab8e", - "address": "erd1u6fw4egq8pv8ufpk5g3nguyf42hnfknq7w7rfhvrta6p5dss5zdsmn69sz" + "pubkey": "34c40587825bee5e0c3e5ade05e3d85532bd30dbfe5a2e7090a3f14fc81c69427bd0f795d68234a25b020daabbed1416e75b81eadf14aade94b6684c411a4d5e2731024f7facb61b55f52115bfdf31349c7a84b1d55664aedd5628eb7a76020c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "a1fe183b6d3b18755d3e4fb809d903ac2bd814ba0a57eaae51e6810b2a5b798c686808681eed4e605f2cf6e39bac9a0fe3dd1825f3f8dc7149310c16afd112bbacda31762486d8d4597d65e6b4bd0f2f8d57d2c3fb1767b1c29edaf01c1c0b15", - "address": "erd1sw93x2nrtsnsa0n3vukjke2vaknwvyyp5e0gsfe5swwxnpf9dxrs6ek2xz" + "pubkey": "3fb9172a72ecc27774d0b908af6a560cd612831c80140175f5fce5fca6614370f8a3a0aa10bac98f20db9fd147ab480fa0d349a2cb329436c8df8f1b9d89e2910537ead4ba6c86e5f509442f3fc997849fdc3734ee8ab0454c7a91c9b866d716", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "7e8ee608fd43806fef1b883867b4250e3d268ff15c377887ec5af02937e5d426da29ce403a452f3d15a55fa3b2ffa51609a0296aaefe4d627955f9c5474c3a9114f507c5176dac90aa6321c71174a62011c805542203bafde753c77a6cc7c68d", - "address": "erd1fh8xt5gw9rvextpdrkwrmwatszyl7sld4mcj0cy6nsmhxs8mpldqmwp4vz" + "pubkey": "4621b763014a99e2c0b571eea33f9b50f96472ca2b0ad5807f29cc7880c18036d5e628a30c79857d2907fc8901a4540be8e0a3f28bf8dc8134602953e56cc485d68dd0141f06533fc7b27b0d8c636ee1128c4a6d32129507be6ce71d8cd85583", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "e8bc4e021386ac00f2c103798c280308edebae5deff00260d097d8e286e37940708f65643a79ec824278d014a6140a086b5a9e6247ee5b9680c141001edb6deebf82d440296355b178a19bb2a78caa65a94f849e80b015c905884dcd3e22bd15", - "address": "erd1jmufwnqe06dvdvy5mse79k04qvm3h9yllhup884udknd4u9l0feq5xqatx" + "pubkey": "92a7a1c460947cda36d47b08f39ccb27923043b5f2c771dbb8fbc372bcf7a3541cc747aad16223fcf726c00f5919b702b5a6697b878df61e9f63a35b76a500512a247c5caca4793f087a4523306784689ae84e00ceee3ee2d1d982526b6bb50b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" }, { - "pubkey": "f5066141eb750c154b4fb048487c38947e2f5a3e591adf0e87af0c9c7858bf0e7b381eb5d1ccad1db2c5d7d255272a0220d562ea5e8c50d77f4c351fc16a1e292c97b025377d8330ebd1018d3171be96ac21d160b10464d7ab9003f936294f18", - "address": "erd16h4f6u5n346kfp77k6lhnxu27c3y4sc0urwcye3q6kjgus28ywpqyfnuh8" + "pubkey": "d60e08476c43c27a12a1779f7362aadc62b9bcd1fee538bdee3a342ad3501d52f8aad736296d1532580887789bc2c418fec7856c1724bb0a61bd23818f52e7881776bbfbe1698d05d053291e7d3708db36431402bc3e3b559b6a3db17c748310", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "8e01cf6844e971286ab70e7c8d20f5ab8d5011f556538692a758335547b6c041f66201645fc6c105b4a5b57a3c4470164e3f779292f82fcf935f0e6af64fac81811e4f967d15192c0bf8c6cb7544721445a55635a981ce312d256dbb0ae0a213", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "42b316de6449c50d46cda15504e6ce80156e666a423c00e316fdc566f5b13fed48d1eafb4d7cf33db76df0f03fba9518a90989831cda0938afc3ff12c4d07b7ca8895b4aee067e138561828b15d70b3981db87a72a9d64158f536528587e7700", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "6ba2c8607cc88f067fedeeb7268dbf9f00aeeff7987b3ac923e756640721f53de28207abeedd6d9d65e007f764f1eb025a5b9a86b369f2d99b0cfed8f3670b49ff75e2445e9044d46ef38594afac3f0c7dbc7f3decb3f9990ff6643514485405", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "6d8bc280079a1521ba4e2bb145715b767d775086a21d6f6df69cfc91498372046eeeaccdb2b9fe34ede725104e7dd3099a7fa5da194b62c2c6a581d7a79845c0b7568d4debcdb0d72077cbec81cc09113696375246e1fbd05ec374fcd647b68d", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a21050025755aa24034544b599fe75bfcaec0a9b0f15a3a57ecd74c5cc21f6b86d7ef7b280b22de53195a7b1e6725c147fa74ff5e410672117986e84ddbf0aae973fa95f9e4012088f72de5e435ab706561d4dec5d4cdec36d5ea70bf2ce7a82", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "7836401c8021e8a504d9b0f050387333380647fa4864cc378234f086fc90e32f9c7ade179dba6fc3cc1d775219941e0d97e676c723497ac972afb6e2a2f319af7f877f8bbf4c8876ae38899a34d262dc9c7ea7c6ed460a55410950f008fe150c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "7bc41d83b22c05df5b9ee502abfdbebcab46256b3237cd8ed95ea3e3534c8a4e48b0921e5875bc57760b0759358e590d140b9f4ee5f3a72908b37f202391fecb0744d11183c4fabbfccb14d6a9285d8b1cc1374fce917f9f2050fc23fe2c4f09", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "1ab88de1f1c19b42cafd8f2e8f5af4d968966d630181772763252b2f134ea5999db6ad56a85ca752a6aea696dec404006ad6f5e73c991134f1280f7a9f1b131d043e0f19fc1bb6a2f739c1e4f7773c1c90efc1cef55e37640aa29b37bfc4a000", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "eccf9b8ee6aa7c8979166c2917b589f8eff0040edce817a62b38221fa88225cb1ad6e71073d9cf4214f7584802bc2517248bc088e4d5d89ebd745cca060a87f5f785915aab95315f20bdfc30ef5a8243a1eef85fb0357101a5e455c9d5c27995", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "99389e3012ae7bc206ed7a090b4da64a0d783b2bcbee5a0c989766d10a1e96927113a73df5d64b6d9a6d650feed9b40a597f47adc38136f2fa6f762f241c045465f55e5d373b232954156c6c194406cc4513422932bf47182aa9b3e9633f0984", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "7df71bfb5a7c2b9b7cb56fe67750e07d58e70b82f00ebcf57b2f34d0527d815b9b4f79a7b9df2f005c62293dd1e1f204eebc9e45862fae294c4bb5804f19a681e97fbd3a7b77a9c07a544546d61d198c612b70b86c4f0740e3a68eac45a35416", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "121b55b2372eb9a031b2998c0f290366ed905c621e7a4e5d7ac0b97ff8942915c3ba459ae727c764fb824d4e670fbe067d84e3a6fa7e21e678e68b2d957fbbb0a278a179e9099a9477cde498a8f9bee4baafb53a875394e8ca09efedf8695f98", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "8a08e422d8554b4cfa704bf1ed1abcec8709c876bd9775eb7fe710653a93f70d58d216660a9fdb5891b3cca9db3d2301e85eb1fd14c46c4e853a6b4ce3766faa3228764aa8aa3561c9c9c834355451a05b055b4fa5a54b32bb91dd36c39f5b95", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "840ebb5a44eca0b7fd28bd48e6788b6488e74c63b66bd524790baa974bb03169fb40ac4b2ada8c6e24a5ca1d08878a107dd77e5404958a506b06d9f529eebea78b4f8886966658525ff07393da654f089496fa304d3980efcd334d8ebbbdd701", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "cfcca1934167035e3f8d36ee7b7cd816c4d0023600ed6cb4b7b6f638f057adceb03ce8b0e5d74e12744262a8ecad86112c8051d9888668210c342ff2dcfd7fd248725e051c333d9e72ca678db0dd4bf4a195a0d5d1983f641a97d1753157df09", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "25724e68c1b2680b1f6c074d13f46f7803be713e0831a41ee4d777d538bca938b38ab1672014ee5234ad83129104ce0d7d7b59e2a59a49f25ee4e3358be45d3abd3e6b9955ba139cdbddeef331213e79479afa27a586a2ab8b697910d4e06c8a", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "cfcfd0acdb1882fecad5683ddc3e4ef4e550f4bdef35775cd40520afbc010456135c496c076274177061540712d8f20cc6aa39b04c30f7b21d62b0f9e1f3462b15730971db4410199ed133a5ab2a535ced5fda2e9e2e6cbb68ba21a80ae0ca85", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "93616db0706b4da11875fe6e8dc9af6af17beaaca72303fbe358644cde36ed75cb58ffa3a22372f344096b36dce622082a40650d5831b7e56256019dd0a40be28871c715de37b4a674e807bc48a8dbdf76793f776881047b674f8e5dd79af088", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "e28c9bd7a3666dcd8549bdae0b8bd8112d462e6ad87e0d672b7a885cbfdb06fe4237d38b5c1366bf0089f0d80f29d91769a2a7a84c4ba5a190620df9c985e2c4d03e50f50c50c5d736778b9effe07060b8046a538ced00d9508f333ef88e3e8e", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "bfbfebb6eb37691b6ebe117a09dc8b65a82325c4f579b5639e6600d6d0357bf69fcc77b6b961d7226ee14337b69ba218af07e708df52690c7e2793f4cd3fb1988ebf3708f73bb1b6d17038fc325d2aa10f6647173dda8e29cd20bcd1280e1c04", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "3e1da253a58f86ba71cd32f36b98abecb55a68b19207db4b2338e7502fe9823abfad44df710d5035ff586464b219fa0f8527289cd6c38d8f051fd3a4bd5c9f50c4c156100224fcc9fc71caadaf71e30065361e94d1ca12a2de34577678d3e286", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "84dc08f7de24dcce1adf8461d4ddaf84916cdc6de10cbedc4a388c0fed1f6f7f96c47ef37cb2188b7cb19c4edd93c8069516ce398316ad2cb69f475f0b4d3ba0ef7efb993a8f956fa33533877589509e17165ab386dca6e9a249a8626188de17", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "264a0c07ad45cc4f0a5001cc89ba69b76e740a7a818d4417dd19f58527671054710bcdc0775e997504e4ebf6eaabbe112ed21fbb0db5890b9ca1994283d9a78eaf1e3a8e3bd5c4935fb04f2d5eca0c56e000b128078403043304b59101dba510", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "bc494086b6a2bb12311286e950fe021d0d2aff7df9e60aa35d37aa4907d6dc2c8833c0f68cb6a06500e546cd0988a00dbd7c68dc55785401bf88f427e11530727bd77816c821c4db3d89cfa66364c636edc218d32502d653ad1a946b643d6083", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "736098f9aa9a61e53b88af6b4e43cba6a43b252cf9ab1fabde9be5aa75e007c364c854d7370c0b5745f86c9ebca6e5114408b99b6dae70a2f83d93fd841fabc201d45d98da168d2965060cd3b17f5d2a3a10eac1162709e35f41da2cf13ce98f", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "36f9f2c6b8ad64070f8c52f6cebbd455ce6e3920df24e49699e3f40dc3d71ae8a954d1227356668095aa1f0f72f5271648f973233fd63e07a3dc2a4bcfe1d0f2be2d360c2431d8db7b4b25fe332fdf4861e03941deb63cdffcd8ec748c3fd310", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "39e2bb3706134f4e8339a990405c2f478992172f0f3e515ac2f20b053934e85d971a6cc509cfa58f2e578079c3a703016f50c8f1df756af3d077c886963d3b73f9f7a572b5a38d7a80fb14e11a8b5b2f49f9f0e76f367eab97a0cb843ff7bc14", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "9676c38a999f847a0f7c9501a471de54ae5e87b6f37086eddefdbd894190b8e5c079ad501f2a3b5cb894480fe8932b13834af113d0f3fd507a865dc5d4a2742cae6940df39342464d3b4a0b1657b22e50b26c1c5615fa03ff948c1471c043e0d", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "eb097ef634170cd919ed2b010a63a9e4d9537803dc3568c1f231bd324e32dd30cbf47826a82657fe8c6bad6c75cb7a193f7a99b407605959c0c36e733d05aba34d5a9736128889584ee5ee7f85af8cf340db4b7198a0663df691a8b3bce6f802", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "4f847acfd5b73c3b064903a24ba4ad2fa9cf73246a5410f16e788c253fd3a6f8b1a9a669bae34f1b5fdea5e7ca29d609634bad8d248ca91eb414c5835285ac418820b3616df61c323b253f1fb664dd19b851f956471354f774d77fda8e4f9407", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "8c914101c6e95a491e08888b4e4babce0fc4540802c442acfb8ee072a3a3b62332ff2a5f20691b88147dc779ed140805f577b5498063da32610bc59170288b1183d23ef0358d1d8e402e94984a9673841756dcacb74c8c342b9674d2bda0c395", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "3bcf7a04a9a940f17b86e99edaea76d1bbfccf6660272f25ed7ad7466f68d538ca2b8383222ef5d99842b90b5d51c31673d0d9446e7358ea96272f8618302d75be3a152e482727e453f209da0444707ffb5c90dcc75f2801213ab606d834c48f", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "cee35ee4b5e6a439a0eaee4e083e70457461e2067df8b968f435b760b3bb783f8fd4392756528255d144ba70fd985a0e89a296440dcb20cce1b451e709cc6643c0659f61e6ce7b3f1e14f02a75bba287e0aa809610568b98fb1be7feae046d01", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "f98f3d185a9d1040d472c0a1aadff1cee9720647d40ea92960345a209624671cd01e2658ff0266d0a2050e64bfcea7002dd6ffacaedf63647d1f8acae9c57b2e75a54b4b751a7d12cdedf75ac0664da3787e98be6eedd7f3141b3055a81a0307", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "f89b11f77d59e5d4c71b5d40f2d4125d72e5ae4103635cda482c6b1e7dd6516191855bb3218b4376d667f300af45a400b67643a23dc6ce3d02ba0e50f1a75fdec50a58e34e425227451efb4f3c956698973fbaa4cbc9fa77b4b84f04f199d204", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a2d2cec062458385b66affcf5aef0440db62697d155540b269f8b29c741ebe16bbed75e96dd2186d52ebc95a920fc914928f975efe98072e78f0da4cad15f3caecf96581242f7d9998efd9df78347e9814fc166ee2639e163c43c7c6b0e12d81", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "256ac3df0ee0de2688700646ba3a694116407381a0c38ab3e4fd17943b564e4fcec769ecda8dcc623f398c88753b2b18d9ea493bc8abfed2808a96bb5eada47da35f1ee6c2c7c5000519942acdc823d14e92fb13bcce963e369f84400291b30b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "c67372ec067c4e8e188ab71a835f8a9eb2980551b90997613c680e6caedc482afc3faa30368171de80b3db1e81c91a02a568f64250b45d629d29046767906ed2c7235ddeb77bc68a3db46eb97d4803d0234536c94c5226d2e9b1e637edea2c86", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "0b5c2ce894d866dc5fb42aad4b1f7ae465693ca8b46640bd79f6bc07eeca31a4c540f693067c7ea06253684ef5f41812a36556dbc80602fc3c729567f32c6bd5cae64aac94adea40d2db270a6f6f0073faa98d6780f528f1ad86a62a388ad615", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "95b4b8a4412685de5a44b3034cea2f1e9f041a78e5a2ac62d5c48b5aeada5a2de6d81f4d5e0052a5bf01967a1590c113904298aa10c82fa1d76d1955b669c273d5f4ee0c22cea8f713ea726064b4cdf70c8c80b99b2803ac296d94134b85ae8e", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "116d5903df283984dac5a0a6e1580779ebed776d88e60c73a20c136e6ca6bd27dacab172c266531521eb371edd21fb06755168b1b532c9d55be505aaf34d3e220cab4bde73039726a723f02408e9ce5b5a1bd14b06e07c67a8b778cb3be9328c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "d43bf08819563c97ebeacdc6dfac7380fe088e194cec8ec58a6d411a22149cab7729282fec33c3d030d20962430c2e0f100446002072fd4ace431f99c6309c12647e0488a884ac384be4b8d8eef02cc1aed9b1c853cfdb0dc3c0b6659bf12d0b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "97215ffbf3eef04dbd9e2ae4a8fbf998847f538cc373947ee95075eb07fd182ae12afb64ab85f01e6806cc044aba7318d5993297434bc01b765ad65043354bbf45e01c14163de4c6482e225ef99c75d46d1649efba9be902c3294ff9e01c4815", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "44ab8292d24a2986919e3433b83b490af39546161c924fd2873da3234f2637ae44c825b27ebf0feae0da04117e38b408a18059c37af95550633e19f5e62f9df247e7407779598e1f507467c8439a016e630e900208fa4d06439c50dc3135e206", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "71eb744087d4c17839a9dc0af73f4a74329bddb75a881678105c9d8749c2636abc5cc6ae22e1042e30f02fa9f03b8c0c823e83405d96edad9953b86317b1783f786da56b77f4718b9af6d7aaf24f71b43b8141de5d0ad88bdb57f154eae85a15", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "b5e14968b6036451ad91e99cdff0fc3b5ce36fff69d1e7554a4797ab3a0236146e464be2616e07151eade97ba52be2180516f12b689130693d9340d777ef1641013e3cb15ad8c7708e1715fa7890068b6cb67af43f315854d9435f909566d196", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "5df989749f2f2c54ff792641ad55be94bd610999a3a50d357439a1235cb41ebb3e0e48626fcc699af055c03902787013ee86b34050a9361a6e32edaf8cec5d2393d978f8329a4d671f0fb03f54c5fe1b98913296974a7996c85631f6a8ff8693", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "e72f1415b8914e5c30ed6a0019987cc3df345701cc97df07b882e46995ac5a3f2331eefcd9fc94f315dbbe7ae2eaf10fc9fbbf3747c9913f190794feab0d2a47f28aac533e533b4f0c8074fa573512d45a29375f64eb34cec2e7be5e30204706", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "01c975d77b686f8132c3bd9ae1ca5e7000529b6b1076660e89b885331b146add69baa9a37a08c432be750955ad592715e51ef042a43c036503c64023d9335038ed69ee06ed38c53bc128dbe8e7b0a70dfdeeae3ef9c26a8eaa755770f010eb92", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "22c5da1f98c2a190edabf5cab5677458c2aa83ca48427ecf31ffe0bbcf1ce696da3cb31e1af0ab412de525f67187a10481b065f1499a6a154e937dd53fa2f7be4fe871c930db120a9e4441a069f586bb905fa5fa48327f86ac8f274d18c2a707", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "d4151e4cc770ed40c990d8e264d7711168c613f939632819c6b15066c312d62ad482707e0fea376c310dec4b6a71c911a80050d9623111aa30a1d22e6443196f7c59ca3684b4bdcec76cd82d2a9f3b2740446e85dd976def717f58a57f0c1017", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "c2d4024d97026e8a6eb0e6082be1c3f688b37f4e8fd3693635c2a54f86894cca81a06195f97a46a954273f283a7c48175097069e0e53a6acb45de187dca1cff612f6efa8efa545e85faa77e688bd776446262022eecc79c28808f3a0b63a8b97", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "5d11a0d99414789f037d95fb0e7f06cfcd1c3f5bd128b3a4af472c9050d3fc02b4e12567f6decc40a4f1d3eddb240f18627171794e8c43ee2e16a8f4819bb99b0e4d44a9c5c8b3abc15b17c5bd91ad47ca3a9fede32cdcab9a625cefb09cac15", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a96bfc01f8b6459bb859ae905f163b657045db3dff192b857b0b18a995decb551c293e2af4329a86c0d55c2ddaf78f10f8bb0839f4065e8602e0bb173fecb92bdf8e3bb92113eb5bcf94c040fed7639518103b0b6b09f9795925d0f0d4f7ac06", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "ae313fdd3f1054e87ea77ef422519440f17b1c688532e5e5e999ef010131c1e8b8ccebc5c515d934e8b16bc84480740e34f15f0db740a4dfafdf46327da9d17243aaa5e3870e23fa98a8719abc16305e0a452457ba80648cde1f0e27d0109595", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "fe454c83df148975f3407d709f0903e2c1a7bd5ba8fbadee50386d103c2a24a89303c9576bcd4b3070ffbedbb4454c0213e8467ec53b6d7ea41b633af7da4f2408c4f7bcb78ac25cc8986505d51ca9c607a97bf43aecebf680adc9b95223ff89", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "78ef7f1d524ccb60e3843a6f3cfbfe1deb5979170afca1867ca6495425d605b94a792135f4e60f7c636fdccf8387c50c1d62032d95bfb49cc4339b986f462791e446988fd47e0c170db3b1c2ac4a17c754dbcf2ba9a7e99b811bf1b9fe0a0f09", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "0d750095dca94a5b3a2871188d6336bb89effd3dc925b74f9d1925fc6abd7cc6611cc7349def482f62b4f2074cf0010b855231b70fac6e60bbffe88accdb6abd704b73950e30fd07e60a3799559a124dd85c4fe7f249c206733f8f9923e0a482", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "772ef728202151e29f9f4f3cce2cd4806f0da953b500aaab12630a94180a9d64085b65721b1c59999a621019962a3b0b8cc369cac31b33d416f69be77c47414506aacee211f2bf77a859418d6cd9088b90cc2afaf5c986c6fdb1149ad6ca7b88", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "448dc6795f2ceeb1be9aa78c5156ccf82ed720b5ed08475cf786a821ec7703ce10321d48b22588fdba366a44e5c7db1254de77795e7d1ed4ae434e54d8318c5991af1719ce30ef533259bf053ea15e52e592b70e861c638e694eca0c943a2817", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "751f8049e521fb88560008141c42d572d5976038bee9639d0e99cd79d773b9fd1c224c5e3356bf0d611a1c466efda0170fcbb3d789634b68bcf590d1e8a5f5e40bc795bb285e67eac09a421abff0fc3c192384a43dc643f5aa261d84885a650c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "c0c902dfebb558c13f9e3bdc280d719a10b2ac952ceeb0b4206e2dbfe31e03e5706e930ec7f5620e8be3ad22d7300e0fed175dd6d65c48b6293fee0bb33fee99da6d644791a770cffeb31dda21acf7cf7f667794c5766a0aba9259a1a8def291", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "afc684a6a49f0af9a66dae4b83f93d9901f147f7b285ad022985536092946b09a1038f72c5636358f51a0e377d62cf1078c8fd18e56bd53de83ffab6372408a4777b7827891a6b559ccae8b2fe15a015d82d23557969a8180d4bd4fe5c5f6280", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "f85a71d07adefb198c310b9fa328bedcd01fa691a5590a719d03d727234be441baf1c83e728bc48370de7ff0c03597027998d96513516b0c6477db893f32912ee8501a4c67d2fb10b7e677522156a7b3fbcab6557b2ce13aab54b1603e1a6f92", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "872e6d94dc904c8c1aebe2df128673d04fee19b9384cb2c698a58b2252a538aa4721334fde0b327db899a5edd62cd0175afbfe09a12082b569f7d07c32a48b1c45d8db77dd1d6a074f5986d5e64ed0a3faf1f51c96a1080971b4f6d3c3478d0f", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "bbe5067ea127f77a731b6a1a7fa9287f015080030a3e5da2c2cd96defc2e68bf5e466d8963550d001386b8edda05530d22adf1fbc7ce8abd4f0d4c7ef564082df0e37b5f129141630634097a54423c779e15fde905a9a9de3ea6211843bb1683", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "33541e9224774c99a90a02de258d71c1aaf0e2e59f2b85f3139b777956d57b6e4804ca21846cbd08283758ca0cacb019ef2f5c7330bcdaefde43db5a4837f188b91a762b781a99c2cafbc12d1b75e7be56a1ad8f06cf77c664dcc8aa5bb24115", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a71deaa2a0eabee55264641e65ea464e75def63423f65e8dcfe84b3d37303d6780ed64cc8bde936face45c5639ca9802febd79b77c858cfb12650fd4c4c68d3523650c892f5f974cc6d28a604eabc34ca308a432793d1d0d004fcfeea8fb470e", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "0d6e5f52f67abf306c9c77b5c91469949cdc7130e83a98041e70e799bd55d69a519726608c03b9ea0ba292869c2218073cd41692de90cdc81b37a34ab9a289d71d88251b8a9bcb62ab8fe9d27f0fec49b38c46b43ed5dd4cf0e1abb3185acf0c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "df22db1c928dde1f11b12bf5dfe7dc3146431cc70b6f461cbf77924e5e144070c1991f17c9a912726ba95fecf39f56156557f119691dd4a20cca3d772140d37bfd95cf540ed62a2a6d57a578bfd7b7054a9fce25175db76d4b2cee53989a7581", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a370d7f9c546a097207876dbb9008af08b0d6162ba3e5abcc9d1626c3943fd94dd90b81f21963d2fb145679146ee5013f8d80216b4f1378e96dea35cd9f631dbf0c054b5022e2b6acb53d4bdf6adec2293964ca95d4b7e55e215458f32641390", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "8936e0e8280b04ad716f3f7aca61dd48e03725f18d072d2d02cf590ed53bb45a5b961ecb3da8145deb651807cc9776050b76d6fd0170a2f1d8e4f007c3a3b3c68b6ab3fb5b5c29fbf41fdfb27969139d6df203395cc09f25612e6a601f288514", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "40594b8d0910479a6da6f51d6c50dd984db8a879c379b5843808bf5a5c503f95abe5eff13123d8d8757d99579dda3019457dab833d2e1ae3ae7ac688cc9fb0c629509f92e931f1494293c2fa83dd326346ad0db371b70d757f9054eeed907d97", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "b054a6b1b06dca56bb39c1176774dcbc2728e982106ba9149b50a152cae8934cc3dcfb0cdbd15aa11744435e9e1b85104de0277267ff2c9ac5d9e9ec8457f1d4c3b58201c0874ee10f2b36a010e856bac8d46b50965208bec9a9850f347b009a", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "80c8e5fedaf6c495e1fb77f7646cfe3451b86319db97537737e57bc1c593f9569839a4b3ee8c2eba41a0d96db2ca8618683082e6588a2807ddb0e67ec728345fb8433c2e23a8a739499634158cbb99b45adbb5bd9b49841865cc9e00262d2298", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "c06cd08d4365ec8a6febdf49495c03df0e5aba1f4944c66f4779f53066de4b312320260be97ae93b0996df2dc479bb157fbd868ce1c5b2f5d54f1821cf375e42d516a28acb2f985382765ef4a919d3078b3a1b22946fa7291695870d18c2d818", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "e09a86ad8a82a47b4705718d63e5c7db82305a6bcb1c535e5b4e4c70eb9073ced578d337db5beb09fe80564733bba0095d02e601fb67449ae84fce24e97dba5f4e89446946ac412f8f1387bdbf3cf1db1635b575cda367f6372fc2a871a1328b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "91f6eefb15e81d5ab4293520175d3c32a149e593ccf494192711312d91092c71e5c6d7e19681d4f4df390953d0601a02127a599289ac7d49e3aa8bd38daa2b01674e09019f807eaaa0ce6d08052fb91712d259ca8cbb5cfd95783fecc3c33397", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "0b6b0f4c4928a1295d8bcf78e9800478a790672ab604cb63b81699c31efe127d34965fc96f99b5cf8db3115d092ba90852ad5f4b5115ea369c1bb7a5aab89d6e70b5d25a27ecbe5fbfd026eec7fdc1e7dda1a9df3e756b494691b50087810b91", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "1ab22da457c8f0ad8cbf3023b6dd26726575fc9de68315f5e7cf4773d9cce249763cc1b854fd52f8fd0683f270126306cf95e11a418e786b6ad025b414f302fe14f15bd7328372e7bf4b7600542c81f63836ab550cf2ed758c7f956f4d62c718", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "dd50605bf96a012ac1d190c2698670dd65bb7d9a521b2931c8896608bff3c6c21bafbf248ee43680ecaab46f2441a51349c9b48fee3827b3d082c4ff992707b8823011fe3b08bf21d1733097ffc72cc51e7a6ea4796655d13e1d579742776a14", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "e7a99728a8ff20c000b5b152c4864b9289903cea510956eb383ed956e8865d57ce375d9c68ad59f625f70ac811d15806381792e3e2e263f2e0508283a651ccdd97752e32941fc211a4e3d3b0f496f7554da7bb750505e3fc4adebb2a5c0ac903", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "f30c3fb03410b27a183097372a139178bff9a0495c8157a96774e9a55a6f0c11f3b8c850319dd278e9617fc30319eb030e2b03b39d21546314a920c6d33fcff24bf477f9bd292a53c7b64f5644a28752f6d5f4d204e803b8486e7bc21846a40e", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "23f394c2e721ad7ce0b1aaf0af55505f33b7d1364fef4f5fd72924c4004c056986c12a5e2bd3b431d82933af73141e07f2493ed9bd35af1306484bf5f881cafd362f6368e6837819c34b4367225411fd88bca04f9a6968881d1c96f741b8e395", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "ddc082d0f1d36fd920ddf7d084c6b302e3ac3c367115593f880c2207db7fec8dabccfe25ee1a17a768ae5e8d2ea3fe0179e0cbe0a003a8b28d7e556802926d3949fa9799cba43e3c08a18050b42be8ec29630bab30e91f74d635e059810d8d8d", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "702a20fe6a80cdd74fc4e9908045c70bc4d54ec744e4aa76108cbef202583bcf38e82b4153c983d72fabd51d88ebca1888682db8ed4d7edef43b76a17984613d47cb92458aa573b93e3867b0831fff97383533c0c3d3f21dad9365dfd537ff01", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "9e74a03c4a2327e824870c8eaf60560fef543a2c1a36531486c16ba240ea8ad9847d4d58cdd9c77c0ace0a22f07a730ca5f12a0426f7eec1be0c9ff7b2c22264dacd84dcf6afe2e2d76a74fbecbc7ac9df9b0c445e3d2c369ec15d9ecacda287", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "1106b4ec08e9d8dea05bd48d95f892b1209c8f50e4c3c738e89885733b5cf0739ae9b50b918ce98d83080bd9fa7ae9093f403850be90ac3ef178b0bc7051448587b88bd19dab40aba5f7aac36ad7f43c4e86d67dd7d2d1e33221758ffc754b88", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "8aa77ce67fc86783cfc0a58f3135875a7a5b6819b38960be2f46359dbd27bc305f1326b9dbfcb4f80ab83fa5e0bffa0168f8b76fb63bc7d18c41eff3ecb10fb66869150931aac9e5cf4849a163efca9d2002a4591778cb2f82cdcedbdcba1a0e", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "1f096476ebd7a661f0b64b327443925544259ac6ff40a21a85004bced3d8e552d0451f38408ff8120d5fa158d4669c14cbc10ba50e70c098032e7401f5610b20ffcd0f56aa152de9567c3dd9dc39d32e1e5b88a627928d297db9cf186760f40c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "bada0e7ea65a23e749c3b788f33e2a0e19bebb456e639083933b2ea8e9e3d4087fc4332f06f699683e116ad6859e53070e9d75513113ed7a7a25e473d5815017602bf228bb53c11b66f442b43bb20f917247cd0280e72b0e401b09aafb50c513", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "57f2c4d737e7120f6bfbea744221f4d59d0d105bf6679f8525a549b6cd348d7909984eaa7b2fa15a1e0dc1a7c7b58c15b20020684d131b6387c5db2d106a64602e02af42e2c0f067d0942b31b857270c0a9ff6b950503dd15ae65534a7687282", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "ae6624a69d8e38cdde1a2900ed0488c5d87b853016e40946345336889bc6590ef34ebeb4c7d6726c43905ebc8436d80fc0a249fe290ccaf25909a14e089409ddd78ee1fc5449c972f023402447c040e455371c0a5cf86658678ec1d3c8c22996", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "93289dfe4bccfa07e08b115ead869416f14a3568f56429c8b2d8ecca86fb9b9860990198504c31f1caf1a00a746d1a08c14db70eaab2b1f41107dd6c2a623501049ba8294849d458a5a2a44120c5cc208b6c99371a4ffc3de43f9666cfe09687", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "10b46ce1336e8fc9fbadc821bd89bc38305e853b1cd7035ec085cd2115b4dde23a1cef7b7ddee237654ad52df024d4103929bf19e9a89631c55794f423c5b4796af05b447b4feda69c5cf1d6876d5df8620ae29f17b97a6102baf22b7418c513", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "6485fd1238daae50a9527f929dad8d96bdd967ac9749e3d0b2a7e73bd5f28960227ed914615a95f201df3a9d0ffab514b6f547aaef955201783bdd515920c0ea152b8d044a65ed1114cf7e5b90d00a2bf5eb9599fb214fa0af36426b4db6510b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "69078c35b4eec50f003cd711968d12b3c6d62b957c42ec7a0a50ed4b60479c0d9342b936177708789c795a84cfc9b50219996600621952fa96d4493f5d30b4fccde76504a97539ef4fd5d703346027373adfc651f4c2a8a62805e8d20a84f085", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "74a5efb97e66a87d4873ca4b5203b2fd54b3bceaa0c337c0e55e0748df6a76b53d1a57e1463115768418d4a54a36b705ee817dfd6fd37f001a20be39f3283dad2982d7e52d1a725c06c96a7014425c3e12a9ac54cf46c2666c850688ae041290", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a6a42f7be431280e8274514fa15da1cd20d6e4ec1b8af20cd930772c531e4b79acaa6729b10574d31f26320496b34312e5552e983ca4ad2b23ad7863af08a63906e4cbbf483bf1344816365c1a5d1553001ca2229b8e9127c36d306df7bf5319", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "5a926a164f65ffd6b09471912dfcf79c8857927e9a1ed1c10bd9cce9694c682819efe696cb4245f398b98db8550d1e1839c2ce87b2d3cb6d0e1e38849bf0ee79804821e15636c614ba9c014259a25e954b728047a863d453fc461987bd2f510d", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "0c6a1ad7670b1b1efc1329d04b509634b4cee2853d46a992cd5960addb4942cf118c4ba08b6268e1a8f0a4145f18e4002c9aeebd735a17edd258276d14deccc643f9f1de88e18efb5f0276eaa3c94f885dae2536b28e5b4cb4d68e19465e6880", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "a636d4483abe6ecf0eacc403a02b9aced78fd84214bb392103e8accf217b6475c0ee6200be7e58296cd3f577d17ff101264fd3c83b45eb510e72e905afae8bf493e9be27ef0e5a3474dde34d844d34ed012198fd6fc3b88fa71915f13e6e9884", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "bbf8dcd551f498c8eb80871ac108cbb38cc71c6d20ac644b5157327c0d6f63cb57ba9c4db19c655db392be3218adea152f9b1a1a4c6d2d2b5fa568e65a3d3b0271675f45d0f5632cfe0650308589b810ad36fd0cc17eba4a8e37e7620ea3f397", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "d88d7b5eefe36a975b584cedbd57dc813fc8e4947093971b8d482bc4dc90a73702aeeb853adf2a09014b27cb61949f02c416423bdaa1b4d0f6e8423f586e406144290f787415cb4a101c477726441f0b424a7fa5cc4f8d90e9621b529de1058f", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "e40ebdfc64135b9c82db648517c29e69559e37be3f04e9b9c87dc1f1cd6e080c44ca4cee4f922b192e320f7bb054e604c7b9acc922d5155544bbfe98baf6fc8404763249dc2a114d552368cb88cfc71cb27ca6372afae8e817625a0f9b3bf90a", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "1cf0d7094fbfac9a681066a96c94f3215e768e1865cb4c41a3f6fa95a44f98f9cec88f9d7b8b444c155cc849d42bff04449e1f3363cad89f1ebf0602f80c8bcaa7e0339f4df672899abd3a89df7a39a4a55e61f532c90f9721b1652d1f927b0c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "9c970cc4c0497acc02fa11baf6b4503b320509ff533bce493f76e248329cc28b5d0359c16a75f275f4c5ef13d8d41312e19f6e1b267b4b515c26f6f0611d5b388c4b9af8f77cd11ee3644d5cc58a93e2e5e95b1a6bc1011ff24fa095b345d718", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "3bbd6a13aa9b5d43d2a25d40312b6907861af907c1dafd041723c88d32a3712666724a926e0fac5331bdd2418693b906543ce0a60a4f5b1275359ad92a852c11b68a3f97207f46e96ddde1b60d94df4acd89fd2a32a5afc49ce75c3d6e705893", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "4808b07006d9dee6fd8b0972db07a5a48ce2d412d5aab0ad4ad5cc4fb126d7b277b64214322e47fa59ba3f6a857939098bb2b96d85d2fe2b31a7a8ab4cffb57a4a85824542ae1787e0b2145d8798536b736581241ca9729e644dfedc23cd650d", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "be167928584f470d9d311735fa19582a67fb5dc123017b52db2003b9bd2cdfdb6ef9480414aa4b92c3bdb7d4e91f6a18ee36a040facfc69f419e97422fbe3f72eaf5e1117b6dfc5e2b0d4fb2b09ab3e4e1ae20c84025f5cb6015fc3c9408d382", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "79216b339df2f8149db9df8ef226798aecbe3710776683addf138030469c328a283571ce46f0663e636f0a789f09fc0d6c890d9cd88ed2c065edc830e4db74248536b99504d587d8158f3cf42856fc0e9872c86c3bedfe0f20433d74b1080a0c", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "7786673263e95e8c1133d7e925e5d1bb3b8f5d17c2a335aef1cd80f6885629135e9e6fda6f9ded4381c4bb506028d30a2fb674384fce8544dbc21bbcc4b60a4a55955da9a5b3347d3d977019981d692f7034f6024aa434b6407a91e07dc91e86", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "fe27a74d4c4984651fa086e1c73b7bd97052be7440f1da455e3b7dc63d46bc8936c3a5c2a6944d921f1b47c22ec33610af851e98f74db395022dd5e2609a1604f78435d977681592d0573a08b798c9955ff3ccc5f70fc6802d33700f47138094", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "32b1ea567dc995619fd7e513df82c76eb5cef220c79f6a0f6b366e76e9c052cd9c1f767c2b9282b5efb00a9cdc98d106a5d0faf4d08e75b5c6a7e62a8fda6345e4eb742f6772c4422f13990c648d89bc70494c5e2061fd3102a867e9f0424080", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "f16a175659008fb619cfd6f07ca2cd8883773c75f947d57155e661ef9a4a5d5c113276edf18d2a5a8d7c3b5b787057078da16bd7dafcbd4cabb8a04cb5806c44c327b0330679a4a5fc67908e5a0da537b7c53a8a725471b5c0c090640ae13d12", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "b1cabea39246be7ac85bc79329aca53ebf0c6d186f1a104c463e680f9681b1b3025e1c2fb4147366346f8921a5e46a042b2fff7a4dfeaf10677388811bbb6001e3ecac9aba895bbc6e0bd0b3be755f6485420c8f04fdfeaef6e5d0d801462303", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + }, + { + "pubkey": "55ca7f274b976e7b6f343deb660973d0c7e332e39d6f7cacb953f9b7f0065e5d817c8e3b9f69d21b95204b9753e94f16bfce7854f8c7945120bb4a72b9ccfd9422f5e87f16224ca977ddcdef0394a931c07aef8644cd681db973d8027888930b", + "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" } ] -} +} \ No newline at end of file From fb204deb394f0cd42d5e8b227d2754e26f9e4e58 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 16:29:33 +0300 Subject: [PATCH 71/79] smaller config files --- cmd/node/config/genesis.json | 1290 +------------------- cmd/node/config/genesisSmartContracts.json | 2 +- cmd/node/config/nodesSetup.json | 512 +------- 3 files changed, 68 insertions(+), 1736 deletions(-) diff --git a/cmd/node/config/genesis.json b/cmd/node/config/genesis.json index 4efa6f6d42..1a85c4d306 100644 --- a/cmd/node/config/genesis.json +++ b/cmd/node/config/genesis.json @@ -1,1298 +1,98 @@ [ { - "address": "erd1gsu3v056q4ka9mtfrxw3nnx7wnsgk4tsjrulveuz47hf9hpgwafsyyk7jf", - "supply": "151628787878787878787878903", - "balance": "149128787878787878787878903", + "address": "erd1vfvqxa8geg42qsp3f6nhmu447j5n7ceaww62y4lkjmzv06jdt5ssaru9hx", + "supply": "1667291666666666666666666674", + "balance": "1664791666666666666666666674", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1heea59kkdmuq37ghtu39gp22fh84vy0vlshd6dkmf04a4ushettqy4uhwd", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1x46jdswqyfgr5h4l2lgkk7avydx8thl3thet6htx8pa3ngu50kfstgv5p5", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1tjtt3m0huh5a9jkmhhpu9hwh7ls9pccd2xhyv6s0s9t6r2m5s0cqvlwysa", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1w4hc4q8j8twnq47cr838hkkzfzpfv7gfqkeh073vtgka8xzr9pps7y7qn4", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1rhxtkf438tazahc4tkmhv6tx6xejacqcyl9sfjh7de9teh8gjh4sqs5cl3", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd12g7px93mzj808dw0edf05zp7lxdq9zdafuj7q3atmdpje0v9clgs0nqj2q", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd17xzxe9lhyd8crn4tsdarw23c7dptu498p3vajcv65hzw79mth29q47chvn", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd17g5jmjpdlhq5fygg8qs8u85cmud7g6uc0f0yhz7k5734tcp64p0sdak5au", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1hyuyaw87k9c8nh48lxmhlgpzyph7asc8gtf2zusa4hcd6hsxzl0qrkxlw6", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd12epqk0m225ushnvrey9tz5pp3cftt6h85xtsqcz93x369mnckx3sj4jt2m", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1qwvs9rr2h9epd7h3ft8wd556qfgqw9tzswrh8ev6enty5cd2tggs29wugu", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1t8ztgmvu0hr0tu686kmxj4artk08njsjgpdz9plakcd09vk698cqgz2tvq", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd123djyzelgvkw2jtk9m6jpqpm0xzlc6fcl89lctwgdgrw33terdaqjt7tqq", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1qac8llthxn8965t2adtkctjyhqfnku9mgzdqulvkkpxmdmj83xkqfyqh48", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1h0dyclgzu9d0086sqn25chncq4lxrznrt4kkeyc3qvc26t6e0jqsf2cze5", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1gxg3nnnlc7muq92auyku5un9e3a0x6q76ge6w4qtmt526sc28yfsa7shnn", + "supply": "1667291666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj", "value": "2500000000000000000000000" } }, { - "address": "erd1e828y6e0c88xql7x7vzysy505znea24k8ym8ltwgh6t2k9uj00zsk5vynm", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10r8gz93suswmekrw92nht0xvu6rsqsurhyfrhypp5apj7fltq4aqjredfm", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1zxw8p8qy2xpqm0yr2t77dmfk479j4xra0nkar0w2tx7ru2uj4zkq6ztx5d", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1c6n4tcxng5d8glhpd70yu972f25na7s50nvjz8w9md28nx6ehvdspwdejr", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1vdn26mcwx85j2se2ugu7k5zqnm08wpe5wjgh4kn8e5mle4samzpsfutxva", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1aewp0su49yp4z4z5xfy5dm82v88h09dh9my0m6u5fs5na6jmkxsqc7f76s", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1tqyerea7lxmdllu3v7k5vhexcyv8wumf8fykgxae64z9fea7kpaq3rttd7", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1stmgjznrwrrc5pgetm7g56d452dwhrf9uxvs9vd775ptscm26m2q4n6smz", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd18mnvj42ukmhzz9c8r6l8zkd0y8uwt8l5qzmskxp79lvvk8hzs5tsqcuhe5", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1a4jqqqckp8kyktnrr8682rppsuryxnlyw502nj7pa3c6aedkeq8spr9knt", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1jz33au4lu5eyv6cx70rzs60jnqh62g559utv00z4q72z6ryll6mqeh2a6j", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1k6xe5rgxlaxvmpj0fs00vw22rqtv2z6d69x0et7ljeef3uatm42sr64g9w", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1q9d8u5ka5jsz93qwd2cnj6sz9w9k68uehhph4r2qfsqhxq9nsflsf0hajy", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd14940v2285g4ff3uqlsp86pehva8n3nna0u9t3f0umjf4hxqlqwrsuvg0kf", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10yvczhthh85k35lrsm74fcpegztpwnkyprz0jldt8wfavc27wqyq64ap8l", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1fg0yjdvh0ejeq79avuygrstghgz2guldg2z7hm98es0l7qgls42s29ycs7", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1f42duudjaehtz9fuunzht277y2859nwagvph58y0ksnnt2af4kqsupn0c3", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd170eld09x604gsfduuke2ew20fzq8ujwp4w2zeldytx88aw63fg7q8w3gyz", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1az84ef3mafn6uplkqhew2hn5cly9ng6lkphmntk9rf5298p3q5xq98ny8g", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1gsvpwqdq265udqzqr7aacyr5fv2789k24x7t9ugc06g7fvsfnpxsvu3qyf", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd18s6krt2wnzsu78jkdr8gky4fqzkltg5324vl2su2tv64x5cj8jtquv4y56", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd15x2r38terhqn4m98a7zdglnr68dz8cg6tju0d4rtu437glyznrqs8pkjh9", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1jrpykk3hvryycwcq03k5rdupu94d8pprr78dfpyvkphtfzveka9s9ut53q", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1d9sweja7lmcpfqsm0020u4ww3t4p0c6sfg8uc88jala6x3vqclpsg359mx", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1nk2sl0tcycspe5gn2khh4lxjx5j0lj2j03ejmqkpuyjz5pq88gas2l7mam", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd183wvn5aszcjge0fra8t96zr6r6u0dpcduanerqsmwn590gjg7ccq6yk82y", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1cn59rh2zfk8emumu3r94may7ttl43qrw9s4psvg2evwl6x0c46ksy4ya43", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1h7prds3ta3hj3l6a06qcq2djn56hnvsszne6pq2mgq9j0cfpyuesz29nh9", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd17vun3k0n7s62lzuls98f450qvymrv0sxllvw07z7hgtusf84sn3qjwmnp0", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1dv40ser2f06sfg567rppyr34uh092agncvtcx46wdczftcvkgqzsm9rk2l", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1amqdj3y5rshq4haxqagr9pd533tefx8l7mtmvcs324c4xges5q6swv0258", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1cnvc8nm0mgasu7mgmxlgryj2z54eke8vdt7ap24qdxxp4q4mjgjq8vlna2", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1rqr5lteu45ll6vavt99m2raxsvqayy4wrj86nj0pznf2elqwwngsg05vul", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1d570ntyctu8s50azm20u6qxcpgt2uxnxygshnxqtwwm276ac2j3sma26xy", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1yxv3g4wgnen6a5w8c2em77g4d49q8v9hsu9se34002hyma4xh8usczs7v5", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10k2dpqmjfpv0gsehkjw87t98nythfkaxvljg53d52unxc03dw7pqp3zrd0", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1j0lwme70yd50ue37786rrq5pe2w76qdpfdt0h75gcqjkdtxqx4zspuua9c", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd12mc66p7gtvj8jdcrv38rlyphdl6xruy7d2qmfyws4x7v0ugrj5eqy0274c", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd16r0c84zuklwkrjv8xrp39aqc8m7zve2dalqxekcr48ea2p5vydxq5jk9ez", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1d97yyspmn9tuda68dt7aq8ymjpqnyytpgahtw0k0z4l0pk6mwlqq3gsm62", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1mkrqlzf5upejs4fu9c05hr0zkrnafnl6f0hytyd5q9l3pvyftr2sjx5xmv", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1lp7h77qzg3xle55y4q4wqkjga3u9dffz62utl5hgk4yjl7qdwdvqpljq2p", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd18epr37af3hjgym2rjz7hkwhy943yh2fc8zc8a28l3z98jq3c8fsqsar5vr", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1sdcks3rdmzqf4wewvd7ay3zp7uqhf0n0qpwjuc9efdu7zcl7z5sqfp5st9", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1fw2nra2t2vw4j2t0mwh92ytfmc7hq7fhkcznjt8ppqeq80z823rs97wpuu", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1e70garz38ew38jvt6a4a6yz0xwvtwcax952n00fxwtd377cnn5cqnsl0dt", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd148zgfnupmra5cgmujkah5d88e2y3z9vmmvec8jldzeq85xvt9msqzxlr02", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd17zuwcwhj67mvjg2hu6nexyr8nrtrxqtpkyh3k98ndk4n0hj9g9zs30u6kf", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1hjs0qfpz7zcegggdv29z0c8lk884580q2s0eaymhhpne5tqzdnpqd2gprj", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd14h0wafvm3pdrgm6zdn5ru5xz2ng2hs6ng35ar6kst89mamamutjsp8c6fs", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd15zrr7y0dydx7pqk4cn5h33snwqkh24jh28wel60x3ekdfp364vks05ctkq", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd12gkhmh30967tlxgk0ec7a2q5nv0exlv2kkdx4gdy2l7lw2fhx76sa9pqge", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1hgc79534rgv4cemsfzajtzy7varsy9k6wxxenj874mxxrk3zg6eqhs9e8c", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1vcq7ee8qq4wa8qvh3wcps5nccnh657uhf67r46l7dws6y63l3das7xecr4", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1kyw0yfe6hr6hf4vj3ud3kvx587xhy2ccxmcswgwvj4dam3vg76vqf7quc0", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1zajxa70mw8lgqzw72g93wtrlcc6skaf4fasx525az0l3gdlhv2rqyd547e", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1nhjkwwrlek7nwkw0p795gkp972u3ncmwk82qz34hl3hvkcuy9a7qs4zf4j", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1ajmkqqsp07wttwftul2jt28d4nyrev8mx0c2v0yyytmukc5t6jdqrgt8fg", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1m2g960p38y8fwg209plnre0ethywgr98jsmca2tfcs4mpewxdn4qg2zfa0", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10htmaddnqctk7egxrf0uqhqx307s0eehmnslnvvpj5d3ya4mt0vqzxsu88", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1z9qhml7esa30s5cjjgkd449smwmcv009mhq3zdednm5qvxqz7hkq8ef72p", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1r6mf6tjaxfvu2zjrlsxdqucumjs5d42ekp54rsgv359m6s9j2efsrzf5qc", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1ydqnv9mq94drcwgy80a6jpm0c2jthekfqpt402vh88wv35qhsrysy8jv0h", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1z37rknaqptaecvqrnu6ntzpwwukz4fgeer4kwdhyuxyy7ttrjkpsagq3kh", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1tr2ramkhygez4fhmz05z0dmnvzh9suwnjmfts26dv9qjh5pclu5qpuh2nh", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1d3qgl6xwmg5v9geup7ceejgclzpwqmflgqfl4229rnmcwl95dppselp75n", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1gkfd8ksurrukf24s2vgvkpzhwwe9qx4cmxqd79zzp6rg8n43aq8s44usnx", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1fmvdaksjp3qz7l7cts8u0d08mrwqtxwer55nt0kwcz3jxrngvals6emq2z", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1hh8u7kqkljugjxu64a4u5tx7pwqy8570jkd5qedt4hsh8kcq2ruqaffy43", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1zkl7qmvpr5gp3052zxks9p7n82ethxshh768vhr3z6kcnz8v3xesp392g3", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1wkv8sard7n5d28sz9838ahjesec4zshvpeeyttjduvhf7t87wl6slqqxql", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1p4jdm03308hyq9fnkpwcqr2l4srn3ph4lvf6lqxnyeq9y8wuqytsxc9v0y", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1h8l7ygdawwlflee7jejxlghpargztyxxx5d956g9vrtaekt4r05qvuafrn", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1wqlw29a2p4mt50zrhlkzsckg5d04qynt2eautaxwt3hxdz45ck7q7znmec", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1qadvfc9lq69js0h70pl5ykcr8lgnanax00juzrw93ywmpxrkvdgqcfwpaw", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd15tfhadl5tjvqen360pkcsv6tq3c0k9p4l58l4adnqht640h636pqvese0h", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1v2sjdna47sp9v7jas6zscq9yf2s0jm39p9m6mcwjaaq7rv3ml4rq4tcal8", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1395trv3gshjn82qsmm3heqh9mgpgfpkursgnpj925ukc52637zuqsnrmlt", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd127cpchua3a4nqgmd7c977nclh8ch7tqxfx4trrlcnzf3kpvxku2spm2k0u", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1asd4mxzm2r8dsjd2m9esgexsqg4su9223pv6nzx47zm66vd45e8se8zpx0", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1xys528vr63wm6dflpmcr0xjwzkwpqlevg68g8g8ruvh0ydfz7lpq74wv57", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1vag4y8kza563q7csfkvfkvt05n2rpt3lhmzqasfleg04l8nkddmsn0yec6", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1dx3308wg2ar2x4jjhak9tr92zy39pcs80ddqke85yege5h2qrvgs78eeg7", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1dlyjs2c806n6axvmsl8rh3r92ku2fj5k74et2ycduhs2fytyhp6s7l86w8", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1mj7z70ugjcuyhl6kx9gtvn4fcdp40eep5thzknqrp6my0c5vdynshtggsk", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1cd9ktvc6a906796kgkj53xpxm32qgtrj6grtmpv82vz7jq08qc4sdj8xa3", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1eep60955eqfmjylysztvcj2cenkey8xjlarlvp48hv8ke33gtaqqgn2mny", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1ju99yygnuwt2qcc9lqule4uyw928f5pk87s3re0nsrx2zgeukskq0ydx6s", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd17v0ejzf67tdumctz8gu5ynq9v85leac9fy9u3xu83m3l5u7etwxqsrl5q9", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd122kkggpzc4s2a78w9p3m34uw0sfamwdnecunt2tdqc7cwchfmcwqcur50x", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1ze20hfejrjf0unzqckt2d92u0mvs77nf8nwtlq2jv6cdeg32j0psewggnt", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd13dej7tajx3ptchlhd6z76qsks3fdk2pu4ya0e75p0lhr6dkp8xjqhgp8wp", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1w6yr6ty2s9wr9qdkrqfc3zh43dgafx42mxdwxng09d0mpdzs634qfevr8z", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1mjft95qcte0w9dp900zst2nnm50kwat5jqvs9vav8jskq5m6tu0q45s5r4", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd15zey3pusy60rhswasja5m7e6f2aefcggkqtwt3l0quurd9xt38cslplk8x", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd12k3qawnpasjl8hk93ggpl8x6ahuvz3w3fepwmuwwexeqzyjynx4su3secy", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd13krturgf3z33mc7vyzn8mjndx48ea3jwhwnsaa83tg06vqgmzsaqqq02zl", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10yrua0n8xwc38ftuwv4dzeset2t9h9hff84ntjedcee4j5usuynqfemsht", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1fnshkk5jdsqwk9yyrn0qeflmheaqk94ranlm5325tezk6swd2r0s2zje25", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd12dtz5uvl6c730glrcq836znrnw9g6jnz5d9ucxr5ztte8q0k6pgq8l3h0j", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1tczqagllxj9aa5pqnzsspqzqqzdyputhd53lpxupejhqaa3549qszngftu", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd13mzzdx7waqph0s5plgg66swl8aajcc58jup5vkdsyhver8mgrn0sp93h4u", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1acngdcqmum329msan3va66cecuy2jsejs39hwdkeewe7gaqduhzs040gsk", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1hdwhn7s4fv0u3mhs9ugtpxgt5wqxk96dtnlfg7dsw4mwfdl2zv4seanymz", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd10ycrvf9ju848vywxzdp4cf7vgc6ytvswpkne895kqec0jnxf9wfq2m9vey", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1pelp27gz67l4z5f07fnkys429pehdesdwaczutyvrzzayvdxecwsrqcp2q", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1lj58ggpefjap8w3z05x5cj8qetrcvcvv7eyacckmfzqehc2tgv5s2435lx", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd129c6yrww92q99d5353kzrrhyevgaaw6k6trsyn88202k745t9ugszvujz3", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1pr8vz9gxuztxem6c0u9fe23lhlq4nxmqy7namp0fw3curdkdmquqaavgjz", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd19dvr8d36ptqy5j5wrr3nevnsnamxj9fnwq0x3juvuv2mtcpampgqm90l5x", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1t9exuhvlqu9m2f85lw0q7gzgwk737ld7ykzrnvnpy4qz0ptm5qzqsd7zh8", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1dsx7473auedse5ksj7j8s8afvah00hcfwnfqcn648wv3jl3eq9gslv6k5z", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1zgc2zj7nyf4pq67nvqamw4dfs6mun0dh8umc4wx993u79zfftawq0ft85k", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1pz7rk9gr33d68ys750hw6n020v3xlzqn760uly5td36g6ydf34msrct7nt", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1fyxsl0vqkjy6yf07htuqxachjmcswcakzc3me9qd9n2tkx53gzfqzza48s", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1wy4h3f8fcna4gsgznmwkaqpfw24kwmcxkyat0mkxvsy37hmqru2quk0ka9", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd14rxsjjqt9q7wvhe7fqdgaak99gmlfn7fky70kmt8x4mc2rqal4dqlcnymh", - "supply": "151628787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt", - "value": "2500000000000000000000000" - } - }, - { - "address": "erd1773jwmsaa0280jhn42j853a6964z324m84e23avjvf7qr2smju8sxhq9vg", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "", - "value": "0" - } - }, - { - "address": "erd1xrnjayplepxtayur6acfadeevjl733ml3wxqthqw2kuw3c6l7nasqk646y", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "", - "value": "0" - } - }, - { - "address": "erd1dq0k7v6p482d0v0rq8p4x9hwmerkfjvx8fgkqepzvk09ez2vr7hqu9d0vu", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", - "stakingvalue": "0", - "delegation": { - "address": "", - "value": "0" - } - }, - { - "address": "erd1q9gmv9r8wuukpnnp5r9rdzuc6nw4eh0xnfea408v00wf54q2ecqqmes8un", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1lly4c0qgl00lg2upkvjytstnge3r89385gkhlfaqyq0te6x3u2rqlz23fs", + "supply": "1664791666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { "address": "", @@ -1300,9 +100,9 @@ } }, { - "address": "erd1x5cfqxpz8lk2njf0qty5hntr2ltdd5xgywsvyk7dzvyuu8z99s5q20gvx6", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd1qwxpsuray9dyg6s7tywgp33wlm4af64h2ls5wmr8dytfr2prhtlsuq5j9a", + "supply": "1664791666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { "address": "", @@ -1310,9 +110,9 @@ } }, { - "address": "erd19y0l7v6j4x0hafqjdcyn6lkkgckv7w24zq6vl9ekyzruq0sqt0nqyd99ta", - "supply": "149128787878787878787878787", - "balance": "149128787878787878787878787", + "address": "erd17lk50mlps7q39wktnvkg3xlzer3nst225twenjqj9880347q06jqt7t5re", + "supply": "1664791666666666666666666666", + "balance": "1664791666666666666666666666", "stakingvalue": "0", "delegation": { "address": "", diff --git a/cmd/node/config/genesisSmartContracts.json b/cmd/node/config/genesisSmartContracts.json index e4175016b6..bf57608f1c 100644 --- a/cmd/node/config/genesisSmartContracts.json +++ b/cmd/node/config/genesisSmartContracts.json @@ -1,6 +1,6 @@ [ { - "owner": "erd1098wtt750w65caywv6v5wyxqdpzgp78axz2j3lpxeq6e9c9uwlys28eh6v", + "owner": "erd16grmckn46ry7fwyvass8e8pz88klazzpc0c5f0pnrv643td4797sgnvjkm", "filename": "./config/genesisContracts/delegation.wasm", "vm-type": "0500", "init-parameters": "0BB8@%auction_sc_address%@0A61D0", diff --git a/cmd/node/config/nodesSetup.json b/cmd/node/config/nodesSetup.json index 17fe6e1039..d4e7333084 100644 --- a/cmd/node/config/nodesSetup.json +++ b/cmd/node/config/nodesSetup.json @@ -1,517 +1,49 @@ { "startTime": 0, "roundDuration": 4000, - "consensusGroupSize": 15, - "minNodesPerShard": 21, + "consensusGroupSize": 3, + "minNodesPerShard": 3, "chainID": "testnet", - "metaChainConsensusGroupSize": 15, - "metaChainMinNodes": 21, + "metaChainConsensusGroupSize": 3, + "metaChainMinNodes": 3, "hysteresis": 0, "adaptivity": false, "initialNodes": [ { - "pubkey": "32dbd94897d1abc7a25bf8eae279514d93cec578434146c59dd2b123d8a2e6258417fc7d3c2f40fa3a9d7c8a18c3951959b978a08433219554a5d9148a59e10074334214f578a79d246c114b64c13efbe294366d0e6eb9a864b7138a9089ee99", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "ea6ad23ec8694dcc42d3f4c8adb81e2b72f08ca33241cb8910044ec1e9cb0da2635a64551319b8a744d2ef4dedf762178d1e57f8a40462378e1205e969018a94214862ec249d61cd9725ba729c1fe1acf7839de7a2ac852582e6e842dde60e13", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "2766b8edd0c857f45ec2a44986be7bf3141ba2c29e37d69d924508fc628a37f8a565f2ee135624b3a6d60ba8edbbbe1618c3aadacd4b2605094874a38da630d397227aa23a3824c590b33a14bf2747c0f0fb8f9f8f23903a26997e3e258cad05", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "27c210a3d9942437ff2e8dfcbb601162caf2deba7f133015b2bdb8b63c5483eb1ec5747b2ed4e3ce4b13ed89888c120365a08003de5e6c76d7c7702ffd06123c096fac4720611e278687bcab717f83bc2dd6e4832ed67aff0546c7a0a69b7000", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "0a46a9a6476710e0c3cfcc35aea3806b4b8640f889a1a1eafb402fd32f7d56c37ac71d73075c0d8e968b3d5adc1cb906c7f5b8b318280182215de268afc2a4c4ef5b1a4db1685c2d214436edcf32e4ab062a0e14af9771936b86fc19e1afac09", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "1d834ece2215313a992dd8ef349908483addaa6d8019c72e1fbc24cdc47784ba881f12b9e4351bc42ebb78ecde5b4313edecfdce31ff29baedb00e0723871e0d02d17582e7a06e9725894267dcdfac930c86feb5d806d5c3917db6ff9eb9d98b", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "4517a20b3c5f28acbdd7e4f856cda980d8e44a7bc96b48d727b45fc9bde7d16f759342503f4e1c872319969076d3a203597268f65d220d8ebf880a181a051ba7a483805d5cafb6d3191b8581da065bf99770f3d481e16179f7c7c1c5f5f2d113", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "b6c9e341d68948b6259c31f64bfe3c6a5a6363db8be3eefd818c24b5bcba00e4a47227cda7c998a57d9ce60c5952b81275e342299e16129b267e4e39a4f4175ac57090060867554646c81d766279a1b6d8aea7b25a4128f81df977cb60f32589", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "34c40587825bee5e0c3e5ade05e3d85532bd30dbfe5a2e7090a3f14fc81c69427bd0f795d68234a25b020daabbed1416e75b81eadf14aade94b6684c411a4d5e2731024f7facb61b55f52115bfdf31349c7a84b1d55664aedd5628eb7a76020c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "9bb55759790bd11971f8368f302d1a933516ea99a8381e3a93c03c753df8455942a85c41b929672474b7d63223cb6511747fc5ee3db4aac84c138f7799f1b19766e8b89b66ee296eda6b5ecac364ae54557338e03bf702ed179587602f693118", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "3fb9172a72ecc27774d0b908af6a560cd612831c80140175f5fce5fca6614370f8a3a0aa10bac98f20db9fd147ab480fa0d349a2cb329436c8df8f1b9d89e2910537ead4ba6c86e5f509442f3fc997849fdc3734ee8ab0454c7a91c9b866d716", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "54bc783b7e1c409f95f51174983f819b7b35ec5f0250098fca14a34ecbeb0ba28c9d5b0ce4cecb7a6d1ce2579922ce139623734e4b3ccc731867224511df11233519130b9922bdbae100e456e9cba23d19ede37f59faac90585f635cde366b19", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "4621b763014a99e2c0b571eea33f9b50f96472ca2b0ad5807f29cc7880c18036d5e628a30c79857d2907fc8901a4540be8e0a3f28bf8dc8134602953e56cc485d68dd0141f06533fc7b27b0d8c636ee1128c4a6d32129507be6ce71d8cd85583", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "beffaa62eb14acc2ee7229432b76a978012631a341fb7cd415a613e0305b99830faaec773a9df990e938dc7704e21f076684d65449c09b5e4a52c97a1591deab90765aacc7e5356b5c5ac53e605fbd638a13e4bf55ee63d40d7ccd08c6fbdf16", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "92a7a1c460947cda36d47b08f39ccb27923043b5f2c771dbb8fbc372bcf7a3541cc747aad16223fcf726c00f5919b702b5a6697b878df61e9f63a35b76a500512a247c5caca4793f087a4523306784689ae84e00ceee3ee2d1d982526b6bb50b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "91876f8a421cc64459116bed6fe3b676104aa4fc94a81626f6b19b4b69739c32093eea35ce1d0f7fbea7923cf5cb2e042cd214dea58143584c8504484921b1a1adba67000e2613e2895a6ebfa8d16ec8ac8d4185ebf58544809cf83d452a598a", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" }, { - "pubkey": "d60e08476c43c27a12a1779f7362aadc62b9bcd1fee538bdee3a342ad3501d52f8aad736296d1532580887789bc2c418fec7856c1724bb0a61bd23818f52e7881776bbfbe1698d05d053291e7d3708db36431402bc3e3b559b6a3db17c748310", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "8e01cf6844e971286ab70e7c8d20f5ab8d5011f556538692a758335547b6c041f66201645fc6c105b4a5b57a3c4470164e3f779292f82fcf935f0e6af64fac81811e4f967d15192c0bf8c6cb7544721445a55635a981ce312d256dbb0ae0a213", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "42b316de6449c50d46cda15504e6ce80156e666a423c00e316fdc566f5b13fed48d1eafb4d7cf33db76df0f03fba9518a90989831cda0938afc3ff12c4d07b7ca8895b4aee067e138561828b15d70b3981db87a72a9d64158f536528587e7700", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "6ba2c8607cc88f067fedeeb7268dbf9f00aeeff7987b3ac923e756640721f53de28207abeedd6d9d65e007f764f1eb025a5b9a86b369f2d99b0cfed8f3670b49ff75e2445e9044d46ef38594afac3f0c7dbc7f3decb3f9990ff6643514485405", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "6d8bc280079a1521ba4e2bb145715b767d775086a21d6f6df69cfc91498372046eeeaccdb2b9fe34ede725104e7dd3099a7fa5da194b62c2c6a581d7a79845c0b7568d4debcdb0d72077cbec81cc09113696375246e1fbd05ec374fcd647b68d", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a21050025755aa24034544b599fe75bfcaec0a9b0f15a3a57ecd74c5cc21f6b86d7ef7b280b22de53195a7b1e6725c147fa74ff5e410672117986e84ddbf0aae973fa95f9e4012088f72de5e435ab706561d4dec5d4cdec36d5ea70bf2ce7a82", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "7836401c8021e8a504d9b0f050387333380647fa4864cc378234f086fc90e32f9c7ade179dba6fc3cc1d775219941e0d97e676c723497ac972afb6e2a2f319af7f877f8bbf4c8876ae38899a34d262dc9c7ea7c6ed460a55410950f008fe150c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "7bc41d83b22c05df5b9ee502abfdbebcab46256b3237cd8ed95ea3e3534c8a4e48b0921e5875bc57760b0759358e590d140b9f4ee5f3a72908b37f202391fecb0744d11183c4fabbfccb14d6a9285d8b1cc1374fce917f9f2050fc23fe2c4f09", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "1ab88de1f1c19b42cafd8f2e8f5af4d968966d630181772763252b2f134ea5999db6ad56a85ca752a6aea696dec404006ad6f5e73c991134f1280f7a9f1b131d043e0f19fc1bb6a2f739c1e4f7773c1c90efc1cef55e37640aa29b37bfc4a000", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "eccf9b8ee6aa7c8979166c2917b589f8eff0040edce817a62b38221fa88225cb1ad6e71073d9cf4214f7584802bc2517248bc088e4d5d89ebd745cca060a87f5f785915aab95315f20bdfc30ef5a8243a1eef85fb0357101a5e455c9d5c27995", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "99389e3012ae7bc206ed7a090b4da64a0d783b2bcbee5a0c989766d10a1e96927113a73df5d64b6d9a6d650feed9b40a597f47adc38136f2fa6f762f241c045465f55e5d373b232954156c6c194406cc4513422932bf47182aa9b3e9633f0984", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "7df71bfb5a7c2b9b7cb56fe67750e07d58e70b82f00ebcf57b2f34d0527d815b9b4f79a7b9df2f005c62293dd1e1f204eebc9e45862fae294c4bb5804f19a681e97fbd3a7b77a9c07a544546d61d198c612b70b86c4f0740e3a68eac45a35416", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "121b55b2372eb9a031b2998c0f290366ed905c621e7a4e5d7ac0b97ff8942915c3ba459ae727c764fb824d4e670fbe067d84e3a6fa7e21e678e68b2d957fbbb0a278a179e9099a9477cde498a8f9bee4baafb53a875394e8ca09efedf8695f98", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "8a08e422d8554b4cfa704bf1ed1abcec8709c876bd9775eb7fe710653a93f70d58d216660a9fdb5891b3cca9db3d2301e85eb1fd14c46c4e853a6b4ce3766faa3228764aa8aa3561c9c9c834355451a05b055b4fa5a54b32bb91dd36c39f5b95", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "840ebb5a44eca0b7fd28bd48e6788b6488e74c63b66bd524790baa974bb03169fb40ac4b2ada8c6e24a5ca1d08878a107dd77e5404958a506b06d9f529eebea78b4f8886966658525ff07393da654f089496fa304d3980efcd334d8ebbbdd701", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "cfcca1934167035e3f8d36ee7b7cd816c4d0023600ed6cb4b7b6f638f057adceb03ce8b0e5d74e12744262a8ecad86112c8051d9888668210c342ff2dcfd7fd248725e051c333d9e72ca678db0dd4bf4a195a0d5d1983f641a97d1753157df09", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "25724e68c1b2680b1f6c074d13f46f7803be713e0831a41ee4d777d538bca938b38ab1672014ee5234ad83129104ce0d7d7b59e2a59a49f25ee4e3358be45d3abd3e6b9955ba139cdbddeef331213e79479afa27a586a2ab8b697910d4e06c8a", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "cfcfd0acdb1882fecad5683ddc3e4ef4e550f4bdef35775cd40520afbc010456135c496c076274177061540712d8f20cc6aa39b04c30f7b21d62b0f9e1f3462b15730971db4410199ed133a5ab2a535ced5fda2e9e2e6cbb68ba21a80ae0ca85", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "93616db0706b4da11875fe6e8dc9af6af17beaaca72303fbe358644cde36ed75cb58ffa3a22372f344096b36dce622082a40650d5831b7e56256019dd0a40be28871c715de37b4a674e807bc48a8dbdf76793f776881047b674f8e5dd79af088", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "e28c9bd7a3666dcd8549bdae0b8bd8112d462e6ad87e0d672b7a885cbfdb06fe4237d38b5c1366bf0089f0d80f29d91769a2a7a84c4ba5a190620df9c985e2c4d03e50f50c50c5d736778b9effe07060b8046a538ced00d9508f333ef88e3e8e", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "bfbfebb6eb37691b6ebe117a09dc8b65a82325c4f579b5639e6600d6d0357bf69fcc77b6b961d7226ee14337b69ba218af07e708df52690c7e2793f4cd3fb1988ebf3708f73bb1b6d17038fc325d2aa10f6647173dda8e29cd20bcd1280e1c04", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "3e1da253a58f86ba71cd32f36b98abecb55a68b19207db4b2338e7502fe9823abfad44df710d5035ff586464b219fa0f8527289cd6c38d8f051fd3a4bd5c9f50c4c156100224fcc9fc71caadaf71e30065361e94d1ca12a2de34577678d3e286", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "84dc08f7de24dcce1adf8461d4ddaf84916cdc6de10cbedc4a388c0fed1f6f7f96c47ef37cb2188b7cb19c4edd93c8069516ce398316ad2cb69f475f0b4d3ba0ef7efb993a8f956fa33533877589509e17165ab386dca6e9a249a8626188de17", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "264a0c07ad45cc4f0a5001cc89ba69b76e740a7a818d4417dd19f58527671054710bcdc0775e997504e4ebf6eaabbe112ed21fbb0db5890b9ca1994283d9a78eaf1e3a8e3bd5c4935fb04f2d5eca0c56e000b128078403043304b59101dba510", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "bc494086b6a2bb12311286e950fe021d0d2aff7df9e60aa35d37aa4907d6dc2c8833c0f68cb6a06500e546cd0988a00dbd7c68dc55785401bf88f427e11530727bd77816c821c4db3d89cfa66364c636edc218d32502d653ad1a946b643d6083", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "736098f9aa9a61e53b88af6b4e43cba6a43b252cf9ab1fabde9be5aa75e007c364c854d7370c0b5745f86c9ebca6e5114408b99b6dae70a2f83d93fd841fabc201d45d98da168d2965060cd3b17f5d2a3a10eac1162709e35f41da2cf13ce98f", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "36f9f2c6b8ad64070f8c52f6cebbd455ce6e3920df24e49699e3f40dc3d71ae8a954d1227356668095aa1f0f72f5271648f973233fd63e07a3dc2a4bcfe1d0f2be2d360c2431d8db7b4b25fe332fdf4861e03941deb63cdffcd8ec748c3fd310", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "39e2bb3706134f4e8339a990405c2f478992172f0f3e515ac2f20b053934e85d971a6cc509cfa58f2e578079c3a703016f50c8f1df756af3d077c886963d3b73f9f7a572b5a38d7a80fb14e11a8b5b2f49f9f0e76f367eab97a0cb843ff7bc14", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "9676c38a999f847a0f7c9501a471de54ae5e87b6f37086eddefdbd894190b8e5c079ad501f2a3b5cb894480fe8932b13834af113d0f3fd507a865dc5d4a2742cae6940df39342464d3b4a0b1657b22e50b26c1c5615fa03ff948c1471c043e0d", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "eb097ef634170cd919ed2b010a63a9e4d9537803dc3568c1f231bd324e32dd30cbf47826a82657fe8c6bad6c75cb7a193f7a99b407605959c0c36e733d05aba34d5a9736128889584ee5ee7f85af8cf340db4b7198a0663df691a8b3bce6f802", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "4f847acfd5b73c3b064903a24ba4ad2fa9cf73246a5410f16e788c253fd3a6f8b1a9a669bae34f1b5fdea5e7ca29d609634bad8d248ca91eb414c5835285ac418820b3616df61c323b253f1fb664dd19b851f956471354f774d77fda8e4f9407", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "8c914101c6e95a491e08888b4e4babce0fc4540802c442acfb8ee072a3a3b62332ff2a5f20691b88147dc779ed140805f577b5498063da32610bc59170288b1183d23ef0358d1d8e402e94984a9673841756dcacb74c8c342b9674d2bda0c395", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "3bcf7a04a9a940f17b86e99edaea76d1bbfccf6660272f25ed7ad7466f68d538ca2b8383222ef5d99842b90b5d51c31673d0d9446e7358ea96272f8618302d75be3a152e482727e453f209da0444707ffb5c90dcc75f2801213ab606d834c48f", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "cee35ee4b5e6a439a0eaee4e083e70457461e2067df8b968f435b760b3bb783f8fd4392756528255d144ba70fd985a0e89a296440dcb20cce1b451e709cc6643c0659f61e6ce7b3f1e14f02a75bba287e0aa809610568b98fb1be7feae046d01", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "f98f3d185a9d1040d472c0a1aadff1cee9720647d40ea92960345a209624671cd01e2658ff0266d0a2050e64bfcea7002dd6ffacaedf63647d1f8acae9c57b2e75a54b4b751a7d12cdedf75ac0664da3787e98be6eedd7f3141b3055a81a0307", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "f89b11f77d59e5d4c71b5d40f2d4125d72e5ae4103635cda482c6b1e7dd6516191855bb3218b4376d667f300af45a400b67643a23dc6ce3d02ba0e50f1a75fdec50a58e34e425227451efb4f3c956698973fbaa4cbc9fa77b4b84f04f199d204", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a2d2cec062458385b66affcf5aef0440db62697d155540b269f8b29c741ebe16bbed75e96dd2186d52ebc95a920fc914928f975efe98072e78f0da4cad15f3caecf96581242f7d9998efd9df78347e9814fc166ee2639e163c43c7c6b0e12d81", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "256ac3df0ee0de2688700646ba3a694116407381a0c38ab3e4fd17943b564e4fcec769ecda8dcc623f398c88753b2b18d9ea493bc8abfed2808a96bb5eada47da35f1ee6c2c7c5000519942acdc823d14e92fb13bcce963e369f84400291b30b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "c67372ec067c4e8e188ab71a835f8a9eb2980551b90997613c680e6caedc482afc3faa30368171de80b3db1e81c91a02a568f64250b45d629d29046767906ed2c7235ddeb77bc68a3db46eb97d4803d0234536c94c5226d2e9b1e637edea2c86", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "0b5c2ce894d866dc5fb42aad4b1f7ae465693ca8b46640bd79f6bc07eeca31a4c540f693067c7ea06253684ef5f41812a36556dbc80602fc3c729567f32c6bd5cae64aac94adea40d2db270a6f6f0073faa98d6780f528f1ad86a62a388ad615", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "95b4b8a4412685de5a44b3034cea2f1e9f041a78e5a2ac62d5c48b5aeada5a2de6d81f4d5e0052a5bf01967a1590c113904298aa10c82fa1d76d1955b669c273d5f4ee0c22cea8f713ea726064b4cdf70c8c80b99b2803ac296d94134b85ae8e", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "116d5903df283984dac5a0a6e1580779ebed776d88e60c73a20c136e6ca6bd27dacab172c266531521eb371edd21fb06755168b1b532c9d55be505aaf34d3e220cab4bde73039726a723f02408e9ce5b5a1bd14b06e07c67a8b778cb3be9328c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "d43bf08819563c97ebeacdc6dfac7380fe088e194cec8ec58a6d411a22149cab7729282fec33c3d030d20962430c2e0f100446002072fd4ace431f99c6309c12647e0488a884ac384be4b8d8eef02cc1aed9b1c853cfdb0dc3c0b6659bf12d0b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "97215ffbf3eef04dbd9e2ae4a8fbf998847f538cc373947ee95075eb07fd182ae12afb64ab85f01e6806cc044aba7318d5993297434bc01b765ad65043354bbf45e01c14163de4c6482e225ef99c75d46d1649efba9be902c3294ff9e01c4815", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "44ab8292d24a2986919e3433b83b490af39546161c924fd2873da3234f2637ae44c825b27ebf0feae0da04117e38b408a18059c37af95550633e19f5e62f9df247e7407779598e1f507467c8439a016e630e900208fa4d06439c50dc3135e206", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "71eb744087d4c17839a9dc0af73f4a74329bddb75a881678105c9d8749c2636abc5cc6ae22e1042e30f02fa9f03b8c0c823e83405d96edad9953b86317b1783f786da56b77f4718b9af6d7aaf24f71b43b8141de5d0ad88bdb57f154eae85a15", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "b5e14968b6036451ad91e99cdff0fc3b5ce36fff69d1e7554a4797ab3a0236146e464be2616e07151eade97ba52be2180516f12b689130693d9340d777ef1641013e3cb15ad8c7708e1715fa7890068b6cb67af43f315854d9435f909566d196", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "5df989749f2f2c54ff792641ad55be94bd610999a3a50d357439a1235cb41ebb3e0e48626fcc699af055c03902787013ee86b34050a9361a6e32edaf8cec5d2393d978f8329a4d671f0fb03f54c5fe1b98913296974a7996c85631f6a8ff8693", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "e72f1415b8914e5c30ed6a0019987cc3df345701cc97df07b882e46995ac5a3f2331eefcd9fc94f315dbbe7ae2eaf10fc9fbbf3747c9913f190794feab0d2a47f28aac533e533b4f0c8074fa573512d45a29375f64eb34cec2e7be5e30204706", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "01c975d77b686f8132c3bd9ae1ca5e7000529b6b1076660e89b885331b146add69baa9a37a08c432be750955ad592715e51ef042a43c036503c64023d9335038ed69ee06ed38c53bc128dbe8e7b0a70dfdeeae3ef9c26a8eaa755770f010eb92", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "22c5da1f98c2a190edabf5cab5677458c2aa83ca48427ecf31ffe0bbcf1ce696da3cb31e1af0ab412de525f67187a10481b065f1499a6a154e937dd53fa2f7be4fe871c930db120a9e4441a069f586bb905fa5fa48327f86ac8f274d18c2a707", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "d4151e4cc770ed40c990d8e264d7711168c613f939632819c6b15066c312d62ad482707e0fea376c310dec4b6a71c911a80050d9623111aa30a1d22e6443196f7c59ca3684b4bdcec76cd82d2a9f3b2740446e85dd976def717f58a57f0c1017", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "c2d4024d97026e8a6eb0e6082be1c3f688b37f4e8fd3693635c2a54f86894cca81a06195f97a46a954273f283a7c48175097069e0e53a6acb45de187dca1cff612f6efa8efa545e85faa77e688bd776446262022eecc79c28808f3a0b63a8b97", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "5d11a0d99414789f037d95fb0e7f06cfcd1c3f5bd128b3a4af472c9050d3fc02b4e12567f6decc40a4f1d3eddb240f18627171794e8c43ee2e16a8f4819bb99b0e4d44a9c5c8b3abc15b17c5bd91ad47ca3a9fede32cdcab9a625cefb09cac15", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a96bfc01f8b6459bb859ae905f163b657045db3dff192b857b0b18a995decb551c293e2af4329a86c0d55c2ddaf78f10f8bb0839f4065e8602e0bb173fecb92bdf8e3bb92113eb5bcf94c040fed7639518103b0b6b09f9795925d0f0d4f7ac06", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "ae313fdd3f1054e87ea77ef422519440f17b1c688532e5e5e999ef010131c1e8b8ccebc5c515d934e8b16bc84480740e34f15f0db740a4dfafdf46327da9d17243aaa5e3870e23fa98a8719abc16305e0a452457ba80648cde1f0e27d0109595", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "fe454c83df148975f3407d709f0903e2c1a7bd5ba8fbadee50386d103c2a24a89303c9576bcd4b3070ffbedbb4454c0213e8467ec53b6d7ea41b633af7da4f2408c4f7bcb78ac25cc8986505d51ca9c607a97bf43aecebf680adc9b95223ff89", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "78ef7f1d524ccb60e3843a6f3cfbfe1deb5979170afca1867ca6495425d605b94a792135f4e60f7c636fdccf8387c50c1d62032d95bfb49cc4339b986f462791e446988fd47e0c170db3b1c2ac4a17c754dbcf2ba9a7e99b811bf1b9fe0a0f09", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "0d750095dca94a5b3a2871188d6336bb89effd3dc925b74f9d1925fc6abd7cc6611cc7349def482f62b4f2074cf0010b855231b70fac6e60bbffe88accdb6abd704b73950e30fd07e60a3799559a124dd85c4fe7f249c206733f8f9923e0a482", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "772ef728202151e29f9f4f3cce2cd4806f0da953b500aaab12630a94180a9d64085b65721b1c59999a621019962a3b0b8cc369cac31b33d416f69be77c47414506aacee211f2bf77a859418d6cd9088b90cc2afaf5c986c6fdb1149ad6ca7b88", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "448dc6795f2ceeb1be9aa78c5156ccf82ed720b5ed08475cf786a821ec7703ce10321d48b22588fdba366a44e5c7db1254de77795e7d1ed4ae434e54d8318c5991af1719ce30ef533259bf053ea15e52e592b70e861c638e694eca0c943a2817", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "751f8049e521fb88560008141c42d572d5976038bee9639d0e99cd79d773b9fd1c224c5e3356bf0d611a1c466efda0170fcbb3d789634b68bcf590d1e8a5f5e40bc795bb285e67eac09a421abff0fc3c192384a43dc643f5aa261d84885a650c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "c0c902dfebb558c13f9e3bdc280d719a10b2ac952ceeb0b4206e2dbfe31e03e5706e930ec7f5620e8be3ad22d7300e0fed175dd6d65c48b6293fee0bb33fee99da6d644791a770cffeb31dda21acf7cf7f667794c5766a0aba9259a1a8def291", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "afc684a6a49f0af9a66dae4b83f93d9901f147f7b285ad022985536092946b09a1038f72c5636358f51a0e377d62cf1078c8fd18e56bd53de83ffab6372408a4777b7827891a6b559ccae8b2fe15a015d82d23557969a8180d4bd4fe5c5f6280", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "f85a71d07adefb198c310b9fa328bedcd01fa691a5590a719d03d727234be441baf1c83e728bc48370de7ff0c03597027998d96513516b0c6477db893f32912ee8501a4c67d2fb10b7e677522156a7b3fbcab6557b2ce13aab54b1603e1a6f92", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "872e6d94dc904c8c1aebe2df128673d04fee19b9384cb2c698a58b2252a538aa4721334fde0b327db899a5edd62cd0175afbfe09a12082b569f7d07c32a48b1c45d8db77dd1d6a074f5986d5e64ed0a3faf1f51c96a1080971b4f6d3c3478d0f", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "bbe5067ea127f77a731b6a1a7fa9287f015080030a3e5da2c2cd96defc2e68bf5e466d8963550d001386b8edda05530d22adf1fbc7ce8abd4f0d4c7ef564082df0e37b5f129141630634097a54423c779e15fde905a9a9de3ea6211843bb1683", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "33541e9224774c99a90a02de258d71c1aaf0e2e59f2b85f3139b777956d57b6e4804ca21846cbd08283758ca0cacb019ef2f5c7330bcdaefde43db5a4837f188b91a762b781a99c2cafbc12d1b75e7be56a1ad8f06cf77c664dcc8aa5bb24115", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a71deaa2a0eabee55264641e65ea464e75def63423f65e8dcfe84b3d37303d6780ed64cc8bde936face45c5639ca9802febd79b77c858cfb12650fd4c4c68d3523650c892f5f974cc6d28a604eabc34ca308a432793d1d0d004fcfeea8fb470e", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "0d6e5f52f67abf306c9c77b5c91469949cdc7130e83a98041e70e799bd55d69a519726608c03b9ea0ba292869c2218073cd41692de90cdc81b37a34ab9a289d71d88251b8a9bcb62ab8fe9d27f0fec49b38c46b43ed5dd4cf0e1abb3185acf0c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "df22db1c928dde1f11b12bf5dfe7dc3146431cc70b6f461cbf77924e5e144070c1991f17c9a912726ba95fecf39f56156557f119691dd4a20cca3d772140d37bfd95cf540ed62a2a6d57a578bfd7b7054a9fce25175db76d4b2cee53989a7581", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a370d7f9c546a097207876dbb9008af08b0d6162ba3e5abcc9d1626c3943fd94dd90b81f21963d2fb145679146ee5013f8d80216b4f1378e96dea35cd9f631dbf0c054b5022e2b6acb53d4bdf6adec2293964ca95d4b7e55e215458f32641390", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "8936e0e8280b04ad716f3f7aca61dd48e03725f18d072d2d02cf590ed53bb45a5b961ecb3da8145deb651807cc9776050b76d6fd0170a2f1d8e4f007c3a3b3c68b6ab3fb5b5c29fbf41fdfb27969139d6df203395cc09f25612e6a601f288514", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "40594b8d0910479a6da6f51d6c50dd984db8a879c379b5843808bf5a5c503f95abe5eff13123d8d8757d99579dda3019457dab833d2e1ae3ae7ac688cc9fb0c629509f92e931f1494293c2fa83dd326346ad0db371b70d757f9054eeed907d97", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "b054a6b1b06dca56bb39c1176774dcbc2728e982106ba9149b50a152cae8934cc3dcfb0cdbd15aa11744435e9e1b85104de0277267ff2c9ac5d9e9ec8457f1d4c3b58201c0874ee10f2b36a010e856bac8d46b50965208bec9a9850f347b009a", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "80c8e5fedaf6c495e1fb77f7646cfe3451b86319db97537737e57bc1c593f9569839a4b3ee8c2eba41a0d96db2ca8618683082e6588a2807ddb0e67ec728345fb8433c2e23a8a739499634158cbb99b45adbb5bd9b49841865cc9e00262d2298", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "c06cd08d4365ec8a6febdf49495c03df0e5aba1f4944c66f4779f53066de4b312320260be97ae93b0996df2dc479bb157fbd868ce1c5b2f5d54f1821cf375e42d516a28acb2f985382765ef4a919d3078b3a1b22946fa7291695870d18c2d818", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "e09a86ad8a82a47b4705718d63e5c7db82305a6bcb1c535e5b4e4c70eb9073ced578d337db5beb09fe80564733bba0095d02e601fb67449ae84fce24e97dba5f4e89446946ac412f8f1387bdbf3cf1db1635b575cda367f6372fc2a871a1328b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "91f6eefb15e81d5ab4293520175d3c32a149e593ccf494192711312d91092c71e5c6d7e19681d4f4df390953d0601a02127a599289ac7d49e3aa8bd38daa2b01674e09019f807eaaa0ce6d08052fb91712d259ca8cbb5cfd95783fecc3c33397", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "0b6b0f4c4928a1295d8bcf78e9800478a790672ab604cb63b81699c31efe127d34965fc96f99b5cf8db3115d092ba90852ad5f4b5115ea369c1bb7a5aab89d6e70b5d25a27ecbe5fbfd026eec7fdc1e7dda1a9df3e756b494691b50087810b91", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "1ab22da457c8f0ad8cbf3023b6dd26726575fc9de68315f5e7cf4773d9cce249763cc1b854fd52f8fd0683f270126306cf95e11a418e786b6ad025b414f302fe14f15bd7328372e7bf4b7600542c81f63836ab550cf2ed758c7f956f4d62c718", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "dd50605bf96a012ac1d190c2698670dd65bb7d9a521b2931c8896608bff3c6c21bafbf248ee43680ecaab46f2441a51349c9b48fee3827b3d082c4ff992707b8823011fe3b08bf21d1733097ffc72cc51e7a6ea4796655d13e1d579742776a14", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "e7a99728a8ff20c000b5b152c4864b9289903cea510956eb383ed956e8865d57ce375d9c68ad59f625f70ac811d15806381792e3e2e263f2e0508283a651ccdd97752e32941fc211a4e3d3b0f496f7554da7bb750505e3fc4adebb2a5c0ac903", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "f30c3fb03410b27a183097372a139178bff9a0495c8157a96774e9a55a6f0c11f3b8c850319dd278e9617fc30319eb030e2b03b39d21546314a920c6d33fcff24bf477f9bd292a53c7b64f5644a28752f6d5f4d204e803b8486e7bc21846a40e", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "23f394c2e721ad7ce0b1aaf0af55505f33b7d1364fef4f5fd72924c4004c056986c12a5e2bd3b431d82933af73141e07f2493ed9bd35af1306484bf5f881cafd362f6368e6837819c34b4367225411fd88bca04f9a6968881d1c96f741b8e395", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "ddc082d0f1d36fd920ddf7d084c6b302e3ac3c367115593f880c2207db7fec8dabccfe25ee1a17a768ae5e8d2ea3fe0179e0cbe0a003a8b28d7e556802926d3949fa9799cba43e3c08a18050b42be8ec29630bab30e91f74d635e059810d8d8d", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "702a20fe6a80cdd74fc4e9908045c70bc4d54ec744e4aa76108cbef202583bcf38e82b4153c983d72fabd51d88ebca1888682db8ed4d7edef43b76a17984613d47cb92458aa573b93e3867b0831fff97383533c0c3d3f21dad9365dfd537ff01", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "9e74a03c4a2327e824870c8eaf60560fef543a2c1a36531486c16ba240ea8ad9847d4d58cdd9c77c0ace0a22f07a730ca5f12a0426f7eec1be0c9ff7b2c22264dacd84dcf6afe2e2d76a74fbecbc7ac9df9b0c445e3d2c369ec15d9ecacda287", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "1106b4ec08e9d8dea05bd48d95f892b1209c8f50e4c3c738e89885733b5cf0739ae9b50b918ce98d83080bd9fa7ae9093f403850be90ac3ef178b0bc7051448587b88bd19dab40aba5f7aac36ad7f43c4e86d67dd7d2d1e33221758ffc754b88", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "8aa77ce67fc86783cfc0a58f3135875a7a5b6819b38960be2f46359dbd27bc305f1326b9dbfcb4f80ab83fa5e0bffa0168f8b76fb63bc7d18c41eff3ecb10fb66869150931aac9e5cf4849a163efca9d2002a4591778cb2f82cdcedbdcba1a0e", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "1f096476ebd7a661f0b64b327443925544259ac6ff40a21a85004bced3d8e552d0451f38408ff8120d5fa158d4669c14cbc10ba50e70c098032e7401f5610b20ffcd0f56aa152de9567c3dd9dc39d32e1e5b88a627928d297db9cf186760f40c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "bada0e7ea65a23e749c3b788f33e2a0e19bebb456e639083933b2ea8e9e3d4087fc4332f06f699683e116ad6859e53070e9d75513113ed7a7a25e473d5815017602bf228bb53c11b66f442b43bb20f917247cd0280e72b0e401b09aafb50c513", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "57f2c4d737e7120f6bfbea744221f4d59d0d105bf6679f8525a549b6cd348d7909984eaa7b2fa15a1e0dc1a7c7b58c15b20020684d131b6387c5db2d106a64602e02af42e2c0f067d0942b31b857270c0a9ff6b950503dd15ae65534a7687282", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "ae6624a69d8e38cdde1a2900ed0488c5d87b853016e40946345336889bc6590ef34ebeb4c7d6726c43905ebc8436d80fc0a249fe290ccaf25909a14e089409ddd78ee1fc5449c972f023402447c040e455371c0a5cf86658678ec1d3c8c22996", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "93289dfe4bccfa07e08b115ead869416f14a3568f56429c8b2d8ecca86fb9b9860990198504c31f1caf1a00a746d1a08c14db70eaab2b1f41107dd6c2a623501049ba8294849d458a5a2a44120c5cc208b6c99371a4ffc3de43f9666cfe09687", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "10b46ce1336e8fc9fbadc821bd89bc38305e853b1cd7035ec085cd2115b4dde23a1cef7b7ddee237654ad52df024d4103929bf19e9a89631c55794f423c5b4796af05b447b4feda69c5cf1d6876d5df8620ae29f17b97a6102baf22b7418c513", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "6485fd1238daae50a9527f929dad8d96bdd967ac9749e3d0b2a7e73bd5f28960227ed914615a95f201df3a9d0ffab514b6f547aaef955201783bdd515920c0ea152b8d044a65ed1114cf7e5b90d00a2bf5eb9599fb214fa0af36426b4db6510b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "69078c35b4eec50f003cd711968d12b3c6d62b957c42ec7a0a50ed4b60479c0d9342b936177708789c795a84cfc9b50219996600621952fa96d4493f5d30b4fccde76504a97539ef4fd5d703346027373adfc651f4c2a8a62805e8d20a84f085", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "74a5efb97e66a87d4873ca4b5203b2fd54b3bceaa0c337c0e55e0748df6a76b53d1a57e1463115768418d4a54a36b705ee817dfd6fd37f001a20be39f3283dad2982d7e52d1a725c06c96a7014425c3e12a9ac54cf46c2666c850688ae041290", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a6a42f7be431280e8274514fa15da1cd20d6e4ec1b8af20cd930772c531e4b79acaa6729b10574d31f26320496b34312e5552e983ca4ad2b23ad7863af08a63906e4cbbf483bf1344816365c1a5d1553001ca2229b8e9127c36d306df7bf5319", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "5a926a164f65ffd6b09471912dfcf79c8857927e9a1ed1c10bd9cce9694c682819efe696cb4245f398b98db8550d1e1839c2ce87b2d3cb6d0e1e38849bf0ee79804821e15636c614ba9c014259a25e954b728047a863d453fc461987bd2f510d", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "0c6a1ad7670b1b1efc1329d04b509634b4cee2853d46a992cd5960addb4942cf118c4ba08b6268e1a8f0a4145f18e4002c9aeebd735a17edd258276d14deccc643f9f1de88e18efb5f0276eaa3c94f885dae2536b28e5b4cb4d68e19465e6880", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "a636d4483abe6ecf0eacc403a02b9aced78fd84214bb392103e8accf217b6475c0ee6200be7e58296cd3f577d17ff101264fd3c83b45eb510e72e905afae8bf493e9be27ef0e5a3474dde34d844d34ed012198fd6fc3b88fa71915f13e6e9884", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "bbf8dcd551f498c8eb80871ac108cbb38cc71c6d20ac644b5157327c0d6f63cb57ba9c4db19c655db392be3218adea152f9b1a1a4c6d2d2b5fa568e65a3d3b0271675f45d0f5632cfe0650308589b810ad36fd0cc17eba4a8e37e7620ea3f397", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "d88d7b5eefe36a975b584cedbd57dc813fc8e4947093971b8d482bc4dc90a73702aeeb853adf2a09014b27cb61949f02c416423bdaa1b4d0f6e8423f586e406144290f787415cb4a101c477726441f0b424a7fa5cc4f8d90e9621b529de1058f", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "e40ebdfc64135b9c82db648517c29e69559e37be3f04e9b9c87dc1f1cd6e080c44ca4cee4f922b192e320f7bb054e604c7b9acc922d5155544bbfe98baf6fc8404763249dc2a114d552368cb88cfc71cb27ca6372afae8e817625a0f9b3bf90a", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "1cf0d7094fbfac9a681066a96c94f3215e768e1865cb4c41a3f6fa95a44f98f9cec88f9d7b8b444c155cc849d42bff04449e1f3363cad89f1ebf0602f80c8bcaa7e0339f4df672899abd3a89df7a39a4a55e61f532c90f9721b1652d1f927b0c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "9c970cc4c0497acc02fa11baf6b4503b320509ff533bce493f76e248329cc28b5d0359c16a75f275f4c5ef13d8d41312e19f6e1b267b4b515c26f6f0611d5b388c4b9af8f77cd11ee3644d5cc58a93e2e5e95b1a6bc1011ff24fa095b345d718", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "3bbd6a13aa9b5d43d2a25d40312b6907861af907c1dafd041723c88d32a3712666724a926e0fac5331bdd2418693b906543ce0a60a4f5b1275359ad92a852c11b68a3f97207f46e96ddde1b60d94df4acd89fd2a32a5afc49ce75c3d6e705893", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "4808b07006d9dee6fd8b0972db07a5a48ce2d412d5aab0ad4ad5cc4fb126d7b277b64214322e47fa59ba3f6a857939098bb2b96d85d2fe2b31a7a8ab4cffb57a4a85824542ae1787e0b2145d8798536b736581241ca9729e644dfedc23cd650d", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "be167928584f470d9d311735fa19582a67fb5dc123017b52db2003b9bd2cdfdb6ef9480414aa4b92c3bdb7d4e91f6a18ee36a040facfc69f419e97422fbe3f72eaf5e1117b6dfc5e2b0d4fb2b09ab3e4e1ae20c84025f5cb6015fc3c9408d382", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "79216b339df2f8149db9df8ef226798aecbe3710776683addf138030469c328a283571ce46f0663e636f0a789f09fc0d6c890d9cd88ed2c065edc830e4db74248536b99504d587d8158f3cf42856fc0e9872c86c3bedfe0f20433d74b1080a0c", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "7786673263e95e8c1133d7e925e5d1bb3b8f5d17c2a335aef1cd80f6885629135e9e6fda6f9ded4381c4bb506028d30a2fb674384fce8544dbc21bbcc4b60a4a55955da9a5b3347d3d977019981d692f7034f6024aa434b6407a91e07dc91e86", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "fe27a74d4c4984651fa086e1c73b7bd97052be7440f1da455e3b7dc63d46bc8936c3a5c2a6944d921f1b47c22ec33610af851e98f74db395022dd5e2609a1604f78435d977681592d0573a08b798c9955ff3ccc5f70fc6802d33700f47138094", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "32b1ea567dc995619fd7e513df82c76eb5cef220c79f6a0f6b366e76e9c052cd9c1f767c2b9282b5efb00a9cdc98d106a5d0faf4d08e75b5c6a7e62a8fda6345e4eb742f6772c4422f13990c648d89bc70494c5e2061fd3102a867e9f0424080", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "f16a175659008fb619cfd6f07ca2cd8883773c75f947d57155e661ef9a4a5d5c113276edf18d2a5a8d7c3b5b787057078da16bd7dafcbd4cabb8a04cb5806c44c327b0330679a4a5fc67908e5a0da537b7c53a8a725471b5c0c090640ae13d12", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "b1cabea39246be7ac85bc79329aca53ebf0c6d186f1a104c463e680f9681b1b3025e1c2fb4147366346f8921a5e46a042b2fff7a4dfeaf10677388811bbb6001e3ecac9aba895bbc6e0bd0b3be755f6485420c8f04fdfeaef6e5d0d801462303", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" - }, - { - "pubkey": "55ca7f274b976e7b6f343deb660973d0c7e332e39d6f7cacb953f9b7f0065e5d817c8e3b9f69d21b95204b9753e94f16bfce7854f8c7945120bb4a72b9ccfd9422f5e87f16224ca977ddcdef0394a931c07aef8644cd681db973d8027888930b", - "address": "erd1qqqqqqqqqqqqqpgqkrptqm0d42mjepcypt8ga8d09r6vghdywlystrfhgt" + "pubkey": "e34f508d647b6bb7747a0d4ce2140e34ae02ff553ec1f8804fdeddb9a6d2608d7cfdb6352d88b0771b8f41e66be36c05d67c585f0971977287d7f959e915f010b628c4b5db465f348a04084c14a3ffc4dd5f6f7eb1cd3709d46b0c0b9163dd8e", + "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" } ] } \ No newline at end of file From 910c99310e9722bc4049ef87aaffec637bff4dc5 Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 17:35:00 +0300 Subject: [PATCH 72/79] claim to return OK if nothing to claim. --- vm/systemSmartContracts/auction.go | 2 +- vm/systemSmartContracts/auction_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/systemSmartContracts/auction.go b/vm/systemSmartContracts/auction.go index ee371b5095..f8095d5193 100644 --- a/vm/systemSmartContracts/auction.go +++ b/vm/systemSmartContracts/auction.go @@ -820,7 +820,7 @@ func (s *stakingAuctionSC) claim(args *vmcommon.ContractCallInput) vmcommon.Retu zero := big.NewInt(0) claimable := big.NewInt(0).Sub(registrationData.TotalStakeValue, registrationData.LockedStake) if claimable.Cmp(zero) <= 0 { - return vmcommon.UserError + return vmcommon.Ok } registrationData.TotalStakeValue.Set(registrationData.LockedStake) diff --git a/vm/systemSmartContracts/auction_test.go b/vm/systemSmartContracts/auction_test.go index b822fef605..547686e5c4 100644 --- a/vm/systemSmartContracts/auction_test.go +++ b/vm/systemSmartContracts/auction_test.go @@ -1436,8 +1436,8 @@ func TestAuctionStakingSC_Claim(t *testing.T) { //do stake stake(t, sc, args.ValidatorSettings.GenesisNodePrice(), receiverAddr, stakerAddress, stakerPubKey, nodesToRunBytes) - //do claim all stake is locked should return UserError - doClaim(t, sc, stakerAddress, receiverAddr, vmcommon.UserError) + //do claim all stake is locked should return Ok + doClaim(t, sc, stakerAddress, receiverAddr, vmcommon.Ok) // do stake to add more money but not lock the stake nonce = 0 From 90cd93a0189c77f295d9b05437abfd7a48e5205e Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 17:53:07 +0300 Subject: [PATCH 73/79] fix after review. --- integrationTests/testProcessorNodeWithMultisigner.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integrationTests/testProcessorNodeWithMultisigner.go b/integrationTests/testProcessorNodeWithMultisigner.go index 2153e9dfdb..cc0c51cfaf 100644 --- a/integrationTests/testProcessorNodeWithMultisigner.go +++ b/integrationTests/testProcessorNodeWithMultisigner.go @@ -113,7 +113,7 @@ func CreateNodesWithNodesCoordinatorWithCacher( } -// CreateNodesWithNodesCoordinatorAndTxKeys +// CreateNodesWithNodesCoordinatorAndTxKeys - func CreateNodesWithNodesCoordinatorAndTxKeys( nodesPerShard int, nbMetaNodes int, @@ -180,6 +180,7 @@ func CreateNodesWithNodesCoordinatorAndTxKeys( return nodesMap } +// CreateNodeWithBLSAndTxKeys - func CreateNodeWithBLSAndTxKeys( nodesPerShard int, nbMetaNodes int, @@ -354,6 +355,7 @@ func CreateNodesWithNodesCoordinatorFactory( return nodesMap } +// CreateNode - func CreateNode( nodesPerShard int, nbMetaNodes int, From 5212957b8684eb671913152929f8852f89be32bf Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 18:08:47 +0300 Subject: [PATCH 74/79] fixed typos, refactored delegationProcessor.sameElements function + added new unit tests. --- core/versioning/versionComparator.go | 2 +- genesis/errors.go | 2 +- .../intermediate/delegationProcessor.go | 33 ++++++------ .../intermediate/delegationProcessor_test.go | 51 +++++++++++++++++++ 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/core/versioning/versionComparator.go b/core/versioning/versionComparator.go index 181919be80..402272b3fb 100644 --- a/core/versioning/versionComparator.go +++ b/core/versioning/versionComparator.go @@ -16,7 +16,7 @@ type versionComparator struct { release string } -// NewVersionComparator return a new version comparator instance +// NewVersionComparator returns a new version comparator instance func NewVersionComparator(providedVersion string) (*versionComparator, error) { vc := &versionComparator{ version: providedVersion, diff --git a/genesis/errors.go b/genesis/errors.go index 13db2c37b3..acf5fecba9 100644 --- a/genesis/errors.go +++ b/genesis/errors.go @@ -131,5 +131,5 @@ var ErrNilQueryService = errors.New("nil query service") // ErrMissingElement signals a missing element event var ErrMissingElement = errors.New("missing element") -// ErrGetVersionFromSC signals that a coll to "version" function on a contract resulted in an unexpected result +// ErrGetVersionFromSC signals that a call to "version" function on a contract resulted in an unexpected result var ErrGetVersionFromSC = errors.New("get version from contract returned an invalid response") diff --git a/genesis/process/intermediate/delegationProcessor.go b/genesis/process/intermediate/delegationProcessor.go index 6e36a62c24..0ea49ea29d 100644 --- a/genesis/process/intermediate/delegationProcessor.go +++ b/genesis/process/intermediate/delegationProcessor.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "math/big" + "sort" "strings" logger "github.com/ElrondNetwork/elrond-go-logger" @@ -426,26 +427,26 @@ func (dp *delegationProcessor) verifyRegisteredNodes(sc genesis.InitialSmartCont nodesAddresses = append(nodesAddresses, node.PubKeyBytes()) } - if len(vmOutputBlsKeys.ReturnData) != len(nodesAddresses) { - return fmt.Errorf("%w staked nodes mismatch: %d found in SC, %d provided", - genesis.ErrWhileVerifyingDelegation, len(vmOutputBlsKeys.ReturnData), len(nodesAddresses)) - } - return dp.sameElements(vmOutputBlsKeys.ReturnData, nodesAddresses) } -func (dp *delegationProcessor) sameElements(slice1 [][]byte, slice2 [][]byte) error { - for _, elem1 := range slice1 { - found := false - for _, elem2 := range slice2 { - if bytes.Equal(elem1, elem2) { - found = true - break - } - } +func (dp *delegationProcessor) sameElements(scReturned [][]byte, loaded [][]byte) error { + if len(scReturned) != len(loaded) { + return fmt.Errorf("%w staked nodes mismatch: %d found in SC, %d provided", + genesis.ErrWhileVerifyingDelegation, len(scReturned), len(loaded)) + } + + sort.Slice(scReturned, func(i, j int) bool { + return bytes.Compare(scReturned[i], scReturned[j]) < 0 + }) + sort.Slice(loaded, func(i, j int) bool { + return bytes.Compare(loaded[i], loaded[j]) < 0 + }) - if !found { - return fmt.Errorf("%w for key %s", genesis.ErrMissingElement, hex.EncodeToString(elem1)) + for i := 0; i < len(loaded); i++ { + if !bytes.Equal(loaded[i], scReturned[i]) { + return fmt.Errorf("%w, found in sc: %s, provided: %s", + genesis.ErrMissingElement, hex.EncodeToString(scReturned[i]), hex.EncodeToString(loaded[i])) } } diff --git a/genesis/process/intermediate/delegationProcessor_test.go b/genesis/process/intermediate/delegationProcessor_test.go index 5acbf7aa84..ec5c906fcd 100644 --- a/genesis/process/intermediate/delegationProcessor_test.go +++ b/genesis/process/intermediate/delegationProcessor_test.go @@ -2,6 +2,7 @@ package intermediate import ( "bytes" + "errors" "fmt" "math/big" "strings" @@ -294,3 +295,53 @@ func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { assert.Nil(t, err) assert.Equal(t, expectedResult, result) } + +//------- SameElements + +func TestSameElements_WrongNumberShouldErr(t *testing.T) { + t.Parallel() + + scReturned := [][]byte{[]byte("buf1"), []byte("buf2"), []byte("buf3")} + loaded := [][]byte{[]byte("buf1"), []byte("buf2")} + + dp := &delegationProcessor{} + err := dp.sameElements(scReturned, loaded) + + assert.True(t, errors.Is(err, genesis.ErrWhileVerifyingDelegation)) +} + +func TestSameElements_MissingFromLoadedShouldErr(t *testing.T) { + t.Parallel() + + scReturned := [][]byte{[]byte("buf5"), []byte("buf2"), []byte("buf3")} + loaded := [][]byte{[]byte("buf1"), []byte("buf3"), []byte("buf2")} + + dp := &delegationProcessor{} + err := dp.sameElements(scReturned, loaded) + + assert.True(t, errors.Is(err, genesis.ErrMissingElement)) +} + +func TestSameElements_DuplicateShouldErr(t *testing.T) { + t.Parallel() + + scReturned := [][]byte{[]byte("buf2"), []byte("buf2"), []byte("buf3")} + loaded := [][]byte{[]byte("buf2"), []byte("buf1"), []byte("buf1")} + + dp := &delegationProcessor{} + err := dp.sameElements(scReturned, loaded) + + assert.True(t, errors.Is(err, genesis.ErrMissingElement)) +} + +func TestSameElements_ShouldWork(t *testing.T) { + t.Parallel() + + scReturned := [][]byte{[]byte("buf1"), []byte("buf2"), []byte("buf3")} + loaded := [][]byte{[]byte("buf2"), []byte("buf3"), []byte("buf1")} + + dp := &delegationProcessor{} + err := dp.sameElements(scReturned, loaded) + + assert.Nil(t, err) +} From e46a703b583e49e02ad11eda22513c52897758c9 Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 19:35:52 +0300 Subject: [PATCH 75/79] small bugfix. --- epochStart/metachain/rewards.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/epochStart/metachain/rewards.go b/epochStart/metachain/rewards.go index a79c8bb0aa..ce3a8af86f 100644 --- a/epochStart/metachain/rewards.go +++ b/epochStart/metachain/rewards.go @@ -292,7 +292,7 @@ func (rc *rewardsCreator) VerifyRewardsMiniBlocks(metaBlock *block.MetaBlock, va } numReceivedRewardsMBs++ - createdMiniBlock := createdMiniBlocks[miniBlockHdr.ReceiverShardID] + createdMiniBlock := getMiniBlockWithReceiverShardID(miniBlockHdr.ReceiverShardID, createdMiniBlocks) createdMBHash, errComputeHash := core.CalculateHash(rc.marshalizer, rc.hasher, createdMiniBlock) if errComputeHash != nil { return errComputeHash @@ -311,6 +311,15 @@ func (rc *rewardsCreator) VerifyRewardsMiniBlocks(metaBlock *block.MetaBlock, va return nil } +func getMiniBlockWithReceiverShardID(shardId uint32, miniBlocks block.MiniBlockSlice) *block.MiniBlock { + for _, miniBlock := range miniBlocks { + if miniBlock.ReceiverShardID == shardId { + return miniBlock + } + } + return nil +} + // CreateMarshalizedData creates the marshalized data to be sent to shards func (rc *rewardsCreator) CreateMarshalizedData(body *block.Body) map[string][][]byte { if check.IfNil(body) { From 8207e3d4c46377a330941ff67839e29db51062d2 Mon Sep 17 00:00:00 2001 From: Robert Sasu Date: Fri, 15 May 2020 19:42:04 +0300 Subject: [PATCH 76/79] small bugfix and unit test --- epochStart/metachain/rewards.go | 4 ++ epochStart/metachain/rewards_test.go | 65 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/epochStart/metachain/rewards.go b/epochStart/metachain/rewards.go index ce3a8af86f..5b4d86d986 100644 --- a/epochStart/metachain/rewards.go +++ b/epochStart/metachain/rewards.go @@ -293,6 +293,10 @@ func (rc *rewardsCreator) VerifyRewardsMiniBlocks(metaBlock *block.MetaBlock, va numReceivedRewardsMBs++ createdMiniBlock := getMiniBlockWithReceiverShardID(miniBlockHdr.ReceiverShardID, createdMiniBlocks) + if createdMiniBlock == nil { + return epochStart.ErrRewardMiniBlockHashDoesNotMatch + } + createdMBHash, errComputeHash := core.CalculateHash(rc.marshalizer, rc.hasher, createdMiniBlock) if errComputeHash != nil { return errComputeHash diff --git a/epochStart/metachain/rewards_test.go b/epochStart/metachain/rewards_test.go index 223a479143..96e4b0633f 100644 --- a/epochStart/metachain/rewards_test.go +++ b/epochStart/metachain/rewards_test.go @@ -296,6 +296,71 @@ func TestRewardsCreator_VerifyRewardsMiniBlocksShouldWork(t *testing.T) { assert.Nil(t, err) } +func TestRewardsCreator_VerifyRewardsMiniBlocksShouldWorkEvenIfNotAllShardsHaveRewards(t *testing.T) { + t.Parallel() + + receivedShardID := uint32(5) + shardCoordinator := &mock.ShardCoordinatorStub{ + ComputeIdCalled: func(address []byte) uint32 { + return receivedShardID + }, + NumberOfShardsCalled: func() uint32 { + return receivedShardID + 1 + }} + args := getRewardsArguments() + args.ShardCoordinator = shardCoordinator + rwd, _ := NewEpochStartRewardsCreator(args) + rwdTx := rewardTx.RewardTx{ + Round: 0, + Value: big.NewInt(100), + RcvAddr: []byte{}, + Epoch: 0, + } + rwdTxHash, _ := core.CalculateHash(&marshal.JsonMarshalizer{}, &mock.HasherMock{}, rwdTx) + + communityRewardTx := rewardTx.RewardTx{ + Round: 0, + Value: big.NewInt(50), + RcvAddr: []byte{17}, + Epoch: 0, + } + commRwdTxHash, _ := core.CalculateHash(&marshal.JsonMarshalizer{}, &mock.HasherMock{}, communityRewardTx) + + bdy := block.MiniBlock{ + TxHashes: [][]byte{commRwdTxHash, rwdTxHash}, + ReceiverShardID: receivedShardID, + SenderShardID: core.MetachainShardId, + Type: block.RewardsBlock, + } + mbh := block.MiniBlockHeader{ + Hash: nil, + SenderShardID: core.MetachainShardId, + ReceiverShardID: receivedShardID, + TxCount: 2, + Type: block.RewardsBlock, + } + mbHash, _ := core.CalculateHash(&marshal.JsonMarshalizer{}, &mock.HasherMock{}, bdy) + mbh.Hash = mbHash + + mb := &block.MetaBlock{ + EpochStart: getDefaultEpochStart(), + MiniBlockHeaders: []block.MiniBlockHeader{ + mbh, + }, + } + valInfo := make(map[uint32][]*state.ValidatorInfo) + valInfo[0] = []*state.ValidatorInfo{ + { + PublicKey: []byte("pubkey"), + ShardId: receivedShardID, + AccumulatedFees: big.NewInt(100), + }, + } + + err := rwd.VerifyRewardsMiniBlocks(mb, valInfo) + assert.Nil(t, err) +} + func TestRewardsCreator_CreateMarshalizedData(t *testing.T) { t.Parallel() From 69d954a41dde192beba917b11bddc5a9f81a9dbd Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 20:27:14 +0300 Subject: [PATCH 77/79] fixes after review --- cmd/node/config/genesisSmartContracts.json | 2 +- cmd/node/config/nodesSetup.json | 6 +++--- genesis/process/argGenesisBlockCreator.go | 7 +++---- genesis/process/genesisBlockCreator.go | 2 ++ genesis/process/intermediate/delegationProcessor.go | 9 +++++---- genesis/process/intermediate/txExecutionProcessor.go | 1 - genesis/process/intermediate/variables.go | 5 ----- 7 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 genesis/process/intermediate/variables.go diff --git a/cmd/node/config/genesisSmartContracts.json b/cmd/node/config/genesisSmartContracts.json index bf57608f1c..c464c313bf 100644 --- a/cmd/node/config/genesisSmartContracts.json +++ b/cmd/node/config/genesisSmartContracts.json @@ -7,4 +7,4 @@ "type": "delegation", "version": "0.2.*" } -] \ No newline at end of file +] diff --git a/cmd/node/config/nodesSetup.json b/cmd/node/config/nodesSetup.json index d4e7333084..9b7d692377 100644 --- a/cmd/node/config/nodesSetup.json +++ b/cmd/node/config/nodesSetup.json @@ -1,12 +1,12 @@ { "startTime": 0, - "roundDuration": 4000, + "roundDuration": 6000, "consensusGroupSize": 3, "minNodesPerShard": 3, "chainID": "testnet", "metaChainConsensusGroupSize": 3, "metaChainMinNodes": 3, - "hysteresis": 0, + "hysteresis": 0.2, "adaptivity": false, "initialNodes": [ { @@ -46,4 +46,4 @@ "address": "erd1qqqqqqqqqqqqqpgqtvuqj62mlpzptgfzp69thcv49z3ruang797s8204fj" } ] -} \ No newline at end of file +} diff --git a/genesis/process/argGenesisBlockCreator.go b/genesis/process/argGenesisBlockCreator.go index e691ac4175..2f6165ddcd 100644 --- a/genesis/process/argGenesisBlockCreator.go +++ b/genesis/process/argGenesisBlockCreator.go @@ -37,10 +37,9 @@ type ArgsGenesisBlockCreator struct { TxLogsProcessor process.TransactionLogProcessor VirtualMachineConfig config.VirtualMachineConfig HardForkConfig config.HardforkConfig - //TODO remove this: at genesis time the genesis block creator should not write other shard's data in the same storage manager - TrieStorageManagers map[string]data.StorageManager - ChainID string - SystemSCConfig config.SystemSmartContractsConfig + TrieStorageManagers map[string]data.StorageManager + ChainID string + SystemSCConfig config.SystemSmartContractsConfig // created component needed only for hardfork importHandler update.ImportHandler } diff --git a/genesis/process/genesisBlockCreator.go b/genesis/process/genesisBlockCreator.go index e73b0d65c0..b636b3aa41 100644 --- a/genesis/process/genesisBlockCreator.go +++ b/genesis/process/genesisBlockCreator.go @@ -213,6 +213,8 @@ func (gbc *genesisBlockCreator) CreateGenesisBlocks() (map[uint32]data.HeaderHan return nil, fmt.Errorf("'%w' while saving genesis block for metachain", err) } + //TODO call here trie pruning on all roothashes not from current shard + return genesisBlocks, nil } diff --git a/genesis/process/intermediate/delegationProcessor.go b/genesis/process/intermediate/delegationProcessor.go index 0ea49ea29d..67c64cd138 100644 --- a/genesis/process/intermediate/delegationProcessor.go +++ b/genesis/process/intermediate/delegationProcessor.go @@ -34,6 +34,7 @@ const setNumNodesFunction = "setNumNodes" const setStakePerNodeFunction = "setStakePerNode" var log = logger.GetOrCreate("genesis/process/intermediate") +var zero = big.NewInt(0) type delegationProcessor struct { genesis.TxExecutionProcessor @@ -98,7 +99,7 @@ func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, er return genesis.DelegationResult{}, err } - _, err = dp.executeManageBlsKeys(smartContracts, dp.setBlsKey, setBlsKeysFunction) + _, err = dp.executeManageBlsKeys(smartContracts, dp.getBlsKey, setBlsKeysFunction) if err != nil { return genesis.DelegationResult{}, err } @@ -109,7 +110,7 @@ func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, er return genesis.DelegationResult{}, err } - dr.NumTotalDelegated, err = dp.executeManageBlsKeys(smartContracts, dp.activate, activateBlsKeysFunction) + dr.NumTotalDelegated, err = dp.executeManageBlsKeys(smartContracts, dp.getBlsKeySig, activateBlsKeysFunction) if err != nil { return genesis.DelegationResult{}, err } @@ -337,11 +338,11 @@ func (dp *delegationProcessor) executeManageBlsKeys( return totalDelegated, nil } -func (dp *delegationProcessor) setBlsKey(node sharding.GenesisNodeInfoHandler) string { +func (dp *delegationProcessor) getBlsKey(node sharding.GenesisNodeInfoHandler) string { return hex.EncodeToString(node.PubKeyBytes()) } -func (dp *delegationProcessor) activate(_ sharding.GenesisNodeInfoHandler) string { +func (dp *delegationProcessor) getBlsKeySig(_ sharding.GenesisNodeInfoHandler) string { mockSignature := []byte("genesis signature") return hex.EncodeToString(mockSignature) diff --git a/genesis/process/intermediate/txExecutionProcessor.go b/genesis/process/intermediate/txExecutionProcessor.go index 55e5c6ca40..9dc46142d1 100644 --- a/genesis/process/intermediate/txExecutionProcessor.go +++ b/genesis/process/intermediate/txExecutionProcessor.go @@ -69,7 +69,6 @@ func (tep *txExecutionProcessor) GetNonce(senderBytes []byte) (uint64, error) { // AccountExists returns if an account exists in the accounts DB func (tep *txExecutionProcessor) AccountExists(address []byte) bool { _, err := tep.accounts.GetExistingAccount(address) - return err == nil } diff --git a/genesis/process/intermediate/variables.go b/genesis/process/intermediate/variables.go deleted file mode 100644 index b2807fba52..0000000000 --- a/genesis/process/intermediate/variables.go +++ /dev/null @@ -1,5 +0,0 @@ -package intermediate - -import "math/big" - -var zero = big.NewInt(0) From 5e2c396ff38bedb1d35ef975c70e83d5c1bef0f2 Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Fri, 15 May 2020 21:14:35 +0300 Subject: [PATCH 78/79] renamed delegationProcessor to standardDelegationProcessor --- ...ssor.go => standardDelegationProcessor.go} | 120 +++++++++--------- ...go => standardDelegationProcessor_test.go} | 84 ++++++------ genesis/process/shardGenesisBlockCreator.go | 4 +- 3 files changed, 104 insertions(+), 104 deletions(-) rename genesis/process/intermediate/{delegationProcessor.go => standardDelegationProcessor.go} (68%) rename genesis/process/intermediate/{delegationProcessor_test.go => standardDelegationProcessor_test.go} (76%) diff --git a/genesis/process/intermediate/delegationProcessor.go b/genesis/process/intermediate/standardDelegationProcessor.go similarity index 68% rename from genesis/process/intermediate/delegationProcessor.go rename to genesis/process/intermediate/standardDelegationProcessor.go index 67c64cd138..c3e0482317 100644 --- a/genesis/process/intermediate/delegationProcessor.go +++ b/genesis/process/intermediate/standardDelegationProcessor.go @@ -16,8 +16,8 @@ import ( "github.com/ElrondNetwork/elrond-go/sharding" ) -// ArgDelegationProcessor is the argument used to construct a delegation processor -type ArgDelegationProcessor struct { +// ArgStandardDelegationProcessor is the argument used to construct a standard delegation processor +type ArgStandardDelegationProcessor struct { Executor genesis.TxExecutionProcessor ShardCoordinator sharding.Coordinator AccountsParser genesis.AccountsParser @@ -36,7 +36,7 @@ const setStakePerNodeFunction = "setStakePerNode" var log = logger.GetOrCreate("genesis/process/intermediate") var zero = big.NewInt(0) -type delegationProcessor struct { +type standardDelegationProcessor struct { genesis.TxExecutionProcessor shardCoordinator sharding.Coordinator accuntsParser genesis.AccountsParser @@ -46,8 +46,8 @@ type delegationProcessor struct { nodePrice *big.Int } -// NewDelegationProcessor returns a new delegation processor instance -func NewDelegationProcessor(arg ArgDelegationProcessor) (*delegationProcessor, error) { +// NewStandardDelegationProcessor returns a new standard delegation processor instance +func NewStandardDelegationProcessor(arg ArgStandardDelegationProcessor) (*standardDelegationProcessor, error) { if check.IfNil(arg.Executor) { return nil, genesis.ErrNilTxExecutionProcessor } @@ -73,7 +73,7 @@ func NewDelegationProcessor(arg ArgDelegationProcessor) (*delegationProcessor, e return nil, genesis.ErrInvalidInitialNodePrice } - return &delegationProcessor{ + return &standardDelegationProcessor{ TxExecutionProcessor: arg.Executor, shardCoordinator: arg.ShardCoordinator, accuntsParser: arg.AccountsParser, @@ -85,8 +85,8 @@ func NewDelegationProcessor(arg ArgDelegationProcessor) (*delegationProcessor, e } // ExecuteDelegation will execute stake, set bls keys and activate on all delegation contracts from this shard -func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, error) { - smartContracts, err := dp.getDelegationScOnCurrentShard() +func (sdp *standardDelegationProcessor) ExecuteDelegation() (genesis.DelegationResult, error) { + smartContracts, err := sdp.getDelegationScOnCurrentShard() if err != nil { return genesis.DelegationResult{}, err } @@ -94,28 +94,28 @@ func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, er return genesis.DelegationResult{}, nil } - err = dp.setDelegationStartParameters(smartContracts) + err = sdp.setDelegationStartParameters(smartContracts) if err != nil { return genesis.DelegationResult{}, err } - _, err = dp.executeManageBlsKeys(smartContracts, dp.getBlsKey, setBlsKeysFunction) + _, err = sdp.executeManageBlsKeys(smartContracts, sdp.getBlsKey, setBlsKeysFunction) if err != nil { return genesis.DelegationResult{}, err } dr := genesis.DelegationResult{} - dr.NumTotalStaked, err = dp.executeStake(smartContracts) + dr.NumTotalStaked, err = sdp.executeStake(smartContracts) if err != nil { return genesis.DelegationResult{}, err } - dr.NumTotalDelegated, err = dp.executeManageBlsKeys(smartContracts, dp.getBlsKeySig, activateBlsKeysFunction) + dr.NumTotalDelegated, err = sdp.executeManageBlsKeys(smartContracts, sdp.getBlsKeySig, activateBlsKeysFunction) if err != nil { return genesis.DelegationResult{}, err } - err = dp.executeVerify(smartContracts) + err = sdp.executeVerify(smartContracts) if err != nil { return genesis.DelegationResult{}, err } @@ -123,14 +123,14 @@ func (dp *delegationProcessor) ExecuteDelegation() (genesis.DelegationResult, er return dr, err } -func (dp *delegationProcessor) getDelegationScOnCurrentShard() ([]genesis.InitialSmartContractHandler, error) { - allSmartContracts, err := dp.smartContractsParser.InitialSmartContractsSplitOnOwnersShards(dp.shardCoordinator) +func (sdp *standardDelegationProcessor) getDelegationScOnCurrentShard() ([]genesis.InitialSmartContractHandler, error) { + allSmartContracts, err := sdp.smartContractsParser.InitialSmartContractsSplitOnOwnersShards(sdp.shardCoordinator) if err != nil { return nil, err } smartContracts := make([]genesis.InitialSmartContractHandler, 0) - smartContractsForCurrentShard := allSmartContracts[dp.shardCoordinator.SelfId()] + smartContractsForCurrentShard := allSmartContracts[sdp.shardCoordinator.SelfId()] for _, sc := range smartContractsForCurrentShard { if sc.GetType() == genesis.DelegationType { smartContracts = append(smartContracts, sc) @@ -139,30 +139,30 @@ func (dp *delegationProcessor) getDelegationScOnCurrentShard() ([]genesis.Initia log.Trace("getDelegationScOnCurrentShard", "num delegation SC", len(smartContracts), - "shard ID", dp.shardCoordinator.SelfId(), + "shard ID", sdp.shardCoordinator.SelfId(), ) return smartContracts, nil } -func (dp *delegationProcessor) setDelegationStartParameters(smartContracts []genesis.InitialSmartContractHandler) error { +func (sdp *standardDelegationProcessor) setDelegationStartParameters(smartContracts []genesis.InitialSmartContractHandler) error { for _, sc := range smartContracts { - delegatedNodes := dp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) + delegatedNodes := sdp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) numNodes := len(delegatedNodes) log.Trace("setDelegationStartParameters", "SC owner", sc.GetOwner(), "SC address", sc.Address(), "num delegated nodes", numNodes, - "node price", dp.nodePrice.String(), - "shard ID", dp.shardCoordinator.SelfId(), + "node price", sdp.nodePrice.String(), + "shard ID", sdp.shardCoordinator.SelfId(), ) - err := dp.executeSetNumNodes(numNodes, sc) + err := sdp.executeSetNumNodes(numNodes, sc) if err != nil { return err } - err = dp.executeSetNodePrice(sc) + err = sdp.executeSetNodePrice(sc) if err != nil { return err } @@ -171,15 +171,15 @@ func (dp *delegationProcessor) setDelegationStartParameters(smartContracts []gen return nil } -func (dp *delegationProcessor) executeSetNumNodes(numNodes int, sc genesis.InitialSmartContractHandler) error { +func (sdp *standardDelegationProcessor) executeSetNumNodes(numNodes int, sc genesis.InitialSmartContractHandler) error { setNumNodesTxData := fmt.Sprintf("%s@%x", setNumNodesFunction, numNodes) - nonce, err := dp.GetNonce(sc.OwnerBytes()) + nonce, err := sdp.GetNonce(sc.OwnerBytes()) if err != nil { return err } - return dp.ExecuteTransaction( + return sdp.ExecuteTransaction( nonce, sc.OwnerBytes(), sc.AddressBytes(), @@ -188,15 +188,15 @@ func (dp *delegationProcessor) executeSetNumNodes(numNodes int, sc genesis.Initi ) } -func (dp *delegationProcessor) executeSetNodePrice(sc genesis.InitialSmartContractHandler) error { - setStakePerNodeTxData := fmt.Sprintf("%s@%x", setStakePerNodeFunction, dp.nodePrice) +func (sdp *standardDelegationProcessor) executeSetNodePrice(sc genesis.InitialSmartContractHandler) error { + setStakePerNodeTxData := fmt.Sprintf("%s@%x", setStakePerNodeFunction, sdp.nodePrice) - nonce, err := dp.GetNonce(sc.OwnerBytes()) + nonce, err := sdp.GetNonce(sc.OwnerBytes()) if err != nil { return err } - return dp.ExecuteTransaction( + return sdp.ExecuteTransaction( nonce, sc.OwnerBytes(), sc.AddressBytes(), @@ -205,11 +205,11 @@ func (dp *delegationProcessor) executeSetNodePrice(sc genesis.InitialSmartContra ) } -func (dp *delegationProcessor) executeStake(smartContracts []genesis.InitialSmartContractHandler) (int, error) { +func (sdp *standardDelegationProcessor) executeStake(smartContracts []genesis.InitialSmartContractHandler) (int, error) { stakedOnDelegation := 0 for _, sc := range smartContracts { - accounts := dp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) + accounts := sdp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) if len(accounts) == 0 { log.Debug("genesis delegation SC was not delegated by any account", "SC owner", sc.GetOwner(), @@ -220,7 +220,7 @@ func (dp *delegationProcessor) executeStake(smartContracts []genesis.InitialSmar totalDelegated := big.NewInt(0) for _, ac := range accounts { - err := dp.stake(ac, sc) + err := sdp.stake(ac, sc) if err != nil { return 0, fmt.Errorf("%w while calling stake function from account %s", err, ac.GetAddress()) } @@ -240,8 +240,8 @@ func (dp *delegationProcessor) executeStake(smartContracts []genesis.InitialSmar return stakedOnDelegation, nil } -func (dp *delegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesis.InitialSmartContractHandler) error { - isIntraShardCall := dp.shardCoordinator.SameShard(ac.AddressBytes(), sc.AddressBytes()) +func (sdp *standardDelegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesis.InitialSmartContractHandler) error { + isIntraShardCall := sdp.shardCoordinator.SameShard(ac.AddressBytes(), sc.AddressBytes()) dh := ac.GetDelegationHandler() if check.IfNil(dh) { @@ -255,14 +255,14 @@ func (dp *delegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesi var nonce = uint64(0) if isIntraShardCall { //intra shard transaction, get current nonce in order to make the tx processor work - nonce, err = dp.GetNonce(ac.AddressBytes()) + nonce, err = sdp.GetNonce(ac.AddressBytes()) if err != nil { return err } } stakeData := fmt.Sprintf("%s@%s", stakeFunction, dh.GetValue().Text(16)) - err = dp.ExecuteTransaction( + err = sdp.ExecuteTransaction( nonce, ac.AddressBytes(), sc.AddressBytes(), @@ -276,7 +276,7 @@ func (dp *delegationProcessor) stake(ac genesis.InitialAccountHandler, sc genesi return nil } -func (dp *delegationProcessor) executeManageBlsKeys( +func (sdp *standardDelegationProcessor) executeManageBlsKeys( smartContracts []genesis.InitialSmartContractHandler, handler func(node sharding.GenesisNodeInfoHandler) string, function string, @@ -284,13 +284,13 @@ func (dp *delegationProcessor) executeManageBlsKeys( log.Trace("executeManageSetBlsKeys", "num delegation SC", len(smartContracts), - "shard ID", dp.shardCoordinator.SelfId(), + "shard ID", sdp.shardCoordinator.SelfId(), "function", function, ) totalDelegated := 0 for _, sc := range smartContracts { - delegatedNodes := dp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) + delegatedNodes := sdp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) lenDelegated := len(delegatedNodes) if lenDelegated == 0 { @@ -307,7 +307,7 @@ func (dp *delegationProcessor) executeManageBlsKeys( "SC owner", sc.GetOwner(), "SC address", sc.Address(), "num nodes", lenDelegated, - "shard ID", dp.shardCoordinator.SelfId(), + "shard ID", sdp.shardCoordinator.SelfId(), "function", function, ) @@ -318,12 +318,12 @@ func (dp *delegationProcessor) executeManageBlsKeys( arguments = append(arguments, arg) } - nonce, err := dp.GetNonce(sc.OwnerBytes()) + nonce, err := sdp.GetNonce(sc.OwnerBytes()) if err != nil { return 0, err } - err = dp.ExecuteTransaction( + err = sdp.ExecuteTransaction( nonce, sc.OwnerBytes(), sc.AddressBytes(), @@ -338,19 +338,19 @@ func (dp *delegationProcessor) executeManageBlsKeys( return totalDelegated, nil } -func (dp *delegationProcessor) getBlsKey(node sharding.GenesisNodeInfoHandler) string { +func (sdp *standardDelegationProcessor) getBlsKey(node sharding.GenesisNodeInfoHandler) string { return hex.EncodeToString(node.PubKeyBytes()) } -func (dp *delegationProcessor) getBlsKeySig(_ sharding.GenesisNodeInfoHandler) string { +func (sdp *standardDelegationProcessor) getBlsKeySig(_ sharding.GenesisNodeInfoHandler) string { mockSignature := []byte("genesis signature") return hex.EncodeToString(mockSignature) } -func (dp *delegationProcessor) executeVerify(smartContracts []genesis.InitialSmartContractHandler) error { +func (sdp *standardDelegationProcessor) executeVerify(smartContracts []genesis.InitialSmartContractHandler) error { for _, sc := range smartContracts { - err := dp.verify(sc) + err := sdp.verify(sc) if err != nil { return fmt.Errorf("%w for contract %s, owner %s", err, sc.Address(), sc.GetOwner()) } @@ -359,13 +359,13 @@ func (dp *delegationProcessor) executeVerify(smartContracts []genesis.InitialSma return nil } -func (dp *delegationProcessor) verify(sc genesis.InitialSmartContractHandler) error { - err := dp.verifyStakedValue(sc) +func (sdp *standardDelegationProcessor) verify(sc genesis.InitialSmartContractHandler) error { + err := sdp.verifyStakedValue(sc) if err != nil { return fmt.Errorf("%w for verifyStakedValue", err) } - err = dp.verifyRegisteredNodes(sc) + err = sdp.verifyRegisteredNodes(sc) if err != nil { return fmt.Errorf("%w for verifyRegisteredNodes", err) } @@ -373,13 +373,13 @@ func (dp *delegationProcessor) verify(sc genesis.InitialSmartContractHandler) er return nil } -func (dp *delegationProcessor) verifyStakedValue(sc genesis.InitialSmartContractHandler) error { +func (sdp *standardDelegationProcessor) verifyStakedValue(sc genesis.InitialSmartContractHandler) error { scQueryStakeValue := &process.SCQuery{ ScAddress: sc.AddressBytes(), FuncName: "getFilledStake", Arguments: [][]byte{}, } - vmOutputStakeValue, err := dp.queryService.ExecuteQuery(scQueryStakeValue) + vmOutputStakeValue, err := sdp.queryService.ExecuteQuery(scQueryStakeValue) if err != nil { return err } @@ -388,7 +388,7 @@ func (dp *delegationProcessor) verifyStakedValue(sc genesis.InitialSmartContract } scStakedValue := big.NewInt(0).SetBytes(vmOutputStakeValue.ReturnData[0]) providedStakedValue := big.NewInt(0) - providedDelegators := dp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) + providedDelegators := sdp.accuntsParser.GetInitialAccountsForDelegated(sc.AddressBytes()) for _, delegator := range providedDelegators { if check.IfNil(delegator) { @@ -411,27 +411,27 @@ func (dp *delegationProcessor) verifyStakedValue(sc genesis.InitialSmartContract return nil } -func (dp *delegationProcessor) verifyRegisteredNodes(sc genesis.InitialSmartContractHandler) error { +func (sdp *standardDelegationProcessor) verifyRegisteredNodes(sc genesis.InitialSmartContractHandler) error { scQueryBlsKeys := &process.SCQuery{ ScAddress: sc.AddressBytes(), FuncName: "getBlsKeys", Arguments: [][]byte{}, } - vmOutputBlsKeys, err := dp.queryService.ExecuteQuery(scQueryBlsKeys) + vmOutputBlsKeys, err := sdp.queryService.ExecuteQuery(scQueryBlsKeys) if err != nil { return err } - delegatedNodes := dp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) + delegatedNodes := sdp.nodesListSplitter.GetDelegatedNodes(sc.AddressBytes()) nodesAddresses := make([][]byte, 0, len(delegatedNodes)) for _, node := range delegatedNodes { nodesAddresses = append(nodesAddresses, node.PubKeyBytes()) } - return dp.sameElements(vmOutputBlsKeys.ReturnData, nodesAddresses) + return sdp.sameElements(vmOutputBlsKeys.ReturnData, nodesAddresses) } -func (dp *delegationProcessor) sameElements(scReturned [][]byte, loaded [][]byte) error { +func (sdp *standardDelegationProcessor) sameElements(scReturned [][]byte, loaded [][]byte) error { if len(scReturned) != len(loaded) { return fmt.Errorf("%w staked nodes mismatch: %d found in SC, %d provided", genesis.ErrWhileVerifyingDelegation, len(scReturned), len(loaded)) @@ -455,6 +455,6 @@ func (dp *delegationProcessor) sameElements(scReturned [][]byte, loaded [][]byte } // IsInterfaceNil returns if underlying object is true -func (dp *delegationProcessor) IsInterfaceNil() bool { - return dp == nil || dp.TxExecutionProcessor == nil +func (sdp *standardDelegationProcessor) IsInterfaceNil() bool { + return sdp == nil || sdp.TxExecutionProcessor == nil } diff --git a/genesis/process/intermediate/delegationProcessor_test.go b/genesis/process/intermediate/standardDelegationProcessor_test.go similarity index 76% rename from genesis/process/intermediate/delegationProcessor_test.go rename to genesis/process/intermediate/standardDelegationProcessor_test.go index ec5c906fcd..25a9d21bee 100644 --- a/genesis/process/intermediate/delegationProcessor_test.go +++ b/genesis/process/intermediate/standardDelegationProcessor_test.go @@ -18,8 +18,8 @@ import ( "github.com/stretchr/testify/assert" ) -func createMockDelegationProcessorArg() ArgDelegationProcessor { - return ArgDelegationProcessor{ +func createMockStandardDelegationProcessorArg() ArgStandardDelegationProcessor { + return ArgStandardDelegationProcessor{ Executor: &mock.TxExecutionProcessorStub{}, ShardCoordinator: &mock.ShardCoordinatorMock{}, AccountsParser: &mock.AccountsParserStub{}, @@ -30,99 +30,99 @@ func createMockDelegationProcessorArg() ArgDelegationProcessor { } } -func TestNewDelegationProcessor_NilExecutorShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilExecutorShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.Executor = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilTxExecutionProcessor, err) } -func TestNewDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilShardCoordinatorShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.ShardCoordinator = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilShardCoordinator, err) } -func TestNewDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilAccountsParserShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.AccountsParser = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilAccountsParser, err) } -func TestNewDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilSmartContractParserShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.SmartContractParser = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilSmartContractParser, err) } -func TestNewDelegationProcessor_NilNodesSplitterShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilNodesSplitterShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.NodesListSplitter = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilNodesListSplitter, err) } -func TestNewDelegationProcessor_NilQueryServiceShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilQueryServiceShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.QueryService = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilQueryService, err) } -func TestNewDelegationProcessor_NilNodePriceShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_NilNodePriceShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.NodePrice = nil - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrNilInitialNodePrice, err) } -func TestNewDelegationProcessor_ZeroNodePriceShouldErr(t *testing.T) { +func TestNewStandardDelegationProcessor_ZeroNodePriceShouldErr(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.NodePrice = big.NewInt(0) - dp, err := NewDelegationProcessor(arg) + dp, err := NewStandardDelegationProcessor(arg) assert.True(t, check.IfNil(dp)) assert.Equal(t, genesis.ErrInvalidInitialNodePrice, err) } -func TestNewDelegationProcessor_ShouldWork(t *testing.T) { +func TestNewStandardDelegationProcessor_ShouldWork(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() - dp, err := NewDelegationProcessor(arg) + arg := createMockStandardDelegationProcessorArg() + dp, err := NewStandardDelegationProcessor(arg) assert.False(t, check.IfNil(dp)) assert.Nil(t, err) @@ -130,11 +130,11 @@ func TestNewDelegationProcessor_ShouldWork(t *testing.T) { //------- ExecuteDelegation -func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) { +func TestStandardDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) { t.Parallel() expectedErr := fmt.Errorf("expected error") - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { assert.Fail(t, "should have not execute a transaction") @@ -148,7 +148,7 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) }, } - dp, _ := NewDelegationProcessor(arg) + dp, _ := NewStandardDelegationProcessor(arg) result, err := dp.ExecuteDelegation() @@ -156,10 +156,10 @@ func TestDelegationProcessor_ExecuteDelegationSplitFailsShouldErr(t *testing.T) assert.Equal(t, genesis.DelegationResult{}, result) } -func TestDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *testing.T) { +func TestStandardDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *testing.T) { t.Parallel() - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { assert.Fail(t, "should have not execute a transaction") @@ -178,7 +178,7 @@ func TestDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *test }, nil }, } - dp, _ := NewDelegationProcessor(arg) + dp, _ := NewStandardDelegationProcessor(arg) result, err := dp.ExecuteDelegation() @@ -186,7 +186,7 @@ func TestDelegationProcessor_ExecuteDelegationNoDelegationScShouldRetNil(t *test assert.Equal(t, genesis.DelegationResult{}, result) } -func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { +func TestStandardDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { t.Parallel() staker1 := []byte("stakerB") @@ -196,7 +196,7 @@ func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { pubkey2 := []byte("pubkey2") pubkey3 := []byte("pubkey3") - arg := createMockDelegationProcessorArg() + arg := createMockStandardDelegationProcessorArg() arg.Executor = &mock.TxExecutionProcessorStub{ ExecuteTransactionCalled: func(nonce uint64, sndAddr []byte, rcvAddress []byte, value *big.Int, data []byte) error { isStakeCall := strings.Contains(string(data), "stake") @@ -283,7 +283,7 @@ func TestDelegationProcessor_ExecuteDelegationStakeShouldWork(t *testing.T) { } }, } - dp, _ := NewDelegationProcessor(arg) + dp, _ := NewStandardDelegationProcessor(arg) result, err := dp.ExecuteDelegation() @@ -304,7 +304,7 @@ func TestSameElements_WrongNumberShouldErr(t *testing.T) { scReturned := [][]byte{[]byte("buf1"), []byte("buf2"), []byte("buf3")} loaded := [][]byte{[]byte("buf1"), []byte("buf2")} - dp := &delegationProcessor{} + dp := &standardDelegationProcessor{} err := dp.sameElements(scReturned, loaded) assert.True(t, errors.Is(err, genesis.ErrWhileVerifyingDelegation)) @@ -316,7 +316,7 @@ func TestSameElements_MissingFromLoadedShouldErr(t *testing.T) { scReturned := [][]byte{[]byte("buf5"), []byte("buf2"), []byte("buf3")} loaded := [][]byte{[]byte("buf1"), []byte("buf3"), []byte("buf2")} - dp := &delegationProcessor{} + dp := &standardDelegationProcessor{} err := dp.sameElements(scReturned, loaded) assert.True(t, errors.Is(err, genesis.ErrMissingElement)) @@ -328,7 +328,7 @@ func TestSameElements_DuplicateShouldErr(t *testing.T) { scReturned := [][]byte{[]byte("buf2"), []byte("buf2"), []byte("buf3")} loaded := [][]byte{[]byte("buf2"), []byte("buf1"), []byte("buf1")} - dp := &delegationProcessor{} + dp := &standardDelegationProcessor{} err := dp.sameElements(scReturned, loaded) assert.True(t, errors.Is(err, genesis.ErrMissingElement)) @@ -340,7 +340,7 @@ func TestSameElements_ShouldWork(t *testing.T) { scReturned := [][]byte{[]byte("buf1"), []byte("buf2"), []byte("buf3")} loaded := [][]byte{[]byte("buf2"), []byte("buf3"), []byte("buf1")} - dp := &delegationProcessor{} + dp := &standardDelegationProcessor{} err := dp.sameElements(scReturned, loaded) assert.Nil(t, err) diff --git a/genesis/process/shardGenesisBlockCreator.go b/genesis/process/shardGenesisBlockCreator.go index 3e2aa82ef4..4150eb4ef9 100644 --- a/genesis/process/shardGenesisBlockCreator.go +++ b/genesis/process/shardGenesisBlockCreator.go @@ -506,7 +506,7 @@ func executeDelegation( return genesis.DelegationResult{}, err } - argDP := intermediate.ArgDelegationProcessor{ + argDP := intermediate.ArgStandardDelegationProcessor{ Executor: txExecutor, ShardCoordinator: arg.ShardCoordinator, AccountsParser: arg.AccountsParser, @@ -516,7 +516,7 @@ func executeDelegation( NodePrice: arg.Economics.GenesisNodePrice(), } - delegationProcessor, err := intermediate.NewDelegationProcessor(argDP) + delegationProcessor, err := intermediate.NewStandardDelegationProcessor(argDP) if err != nil { return genesis.DelegationResult{}, err } From 87548eb69504f6f3c4f78a8e89fcfc6309090aee Mon Sep 17 00:00:00 2001 From: Iulian Pascalau Date: Sun, 17 May 2020 11:12:01 +0300 Subject: [PATCH 79/79] fixes after merge --- integrationTests/vm/systemVM/stakingSC_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integrationTests/vm/systemVM/stakingSC_test.go b/integrationTests/vm/systemVM/stakingSC_test.go index ee6e35f9fb..55faa9d49a 100644 --- a/integrationTests/vm/systemVM/stakingSC_test.go +++ b/integrationTests/vm/systemVM/stakingSC_test.go @@ -13,6 +13,7 @@ import ( "github.com/ElrondNetwork/elrond-go/integrationTests" "github.com/ElrondNetwork/elrond-go/integrationTests/multiShard/endOfEpoch" "github.com/ElrondNetwork/elrond-go/vm/factory" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -300,8 +301,8 @@ func TestStakeWithRewardsAddressAndValidatorStatistics(t *testing.T) { var consensusNodes map[uint32][]*integrationTests.TestProcessorNode for i := uint64(0); i < nbBlocksToProduce; i++ { - for _, nodes := range nodesMap { - integrationTests.UpdateRound(nodes, round) + for _, nodesSlice := range nodesMap { + integrationTests.UpdateRound(nodesSlice, round) } _, _, consensusNodes = integrationTests.AllShardsProposeBlock(round, nonce, nodesMap)