Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions integrationTests/chainSimulator/rewards/rewards_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package rewards

import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"os"
"path"
"testing"
"time"

"github.com/multiversx/mx-chain-core-go/core"
apiCore "github.com/multiversx/mx-chain-core-go/data/api"
"github.com/multiversx/mx-chain-core-go/data/block"
"github.com/multiversx/mx-chain-go/config"
"github.com/multiversx/mx-chain-go/node/chainSimulator"
"github.com/multiversx/mx-chain-go/node/chainSimulator/components/api"
"github.com/stretchr/testify/require"
)

const (
defaultPathToInitialConfig = "../../../cmd/node/config/"
)

func TestRewardsTxsAfterEquivalentMessages(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we consider this a long test as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, changed

startTime := time.Now().Unix()
roundDurationInMillis := uint64(6000)
roundsPerEpoch := core.OptionalUint64{
HasValue: true,
Value: 200,
}

numOfShards := uint32(3)

tempDir := t.TempDir()
cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{
BypassTxSignatureCheck: true,
TempDir: tempDir,
PathToInitialConfig: defaultPathToInitialConfig,
NumOfShards: numOfShards,
GenesisTimestamp: startTime,
RoundDurationInMillis: roundDurationInMillis,
RoundsPerEpoch: roundsPerEpoch,
ApiInterface: api.NewNoApiInterface(),
MinNodesPerShard: 3,
MetaChainMinNodes: 3,
AlterConfigsFunction: func(cfg *config.Configs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove new line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

},
})
require.Nil(t, err)
require.NotNil(t, cs)
defer cs.Close()

targetEpoch := 9
for i := 0; i < targetEpoch; i++ {
if i == 8 {
fmt.Println("here")
}
err = cs.ForceChangeOfEpoch()
require.Nil(t, err)
}

err = cs.GenerateBlocks(210)
require.Nil(t, err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed? or GenerateBlocksUntilEpochIsReached can be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I use that function, more blocks will be generated until I reach epoch 9, with this method, only 30 blocks are generated.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe remove

if i == 8 {
	fmt.Println("here")
}


metaFacadeHandler := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler()

nodesSetupFile := path.Join(tempDir, "config", "nodesSetup.json")
validators, err := readValidatorsAndOwners(nodesSetupFile)
require.Nil(t, err)
fmt.Println(validators)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removed


// find block with rewards transactions, in this range we should find the epoch start block
var metaBlock *apiCore.Block
found := false
for nonce := uint64(210); nonce < 235; nonce++ {
metaBlock, err = metaFacadeHandler.GetBlockByNonce(nonce, apiCore.BlockQueryOptions{
WithTransactions: true,
})
require.Nil(t, err)

isEpochStart := metaBlock.EpochStartInfo != nil
if !isEpochStart {
continue
}

found = true
break
}
require.True(t, found)
require.NotNil(t, metaBlock)

nodesCoordinator := cs.GetNodeHandler(0).GetProcessComponents().NodesCoordinator()

shards := []uint32{0, 1, 2, core.MetachainShardId}

rewardsPerShard := make(map[uint32]*big.Int)
for _, shardID := range shards {
validatorsPerShard, errG := nodesCoordinator.GetAllEligibleValidatorsPublicKeysForShard(8, shardID)
require.Nil(t, errG)

for _, validator := range validatorsPerShard {
owner, ok := validators[hex.EncodeToString([]byte(validator))]
if !ok {
continue
}

for _, mb := range metaBlock.MiniBlocks {
if mb.Type != block.RewardsBlock.String() {
continue
}

for _, tx := range mb.Transactions {
if tx.Receiver != owner {
continue
}
_, ok = rewardsPerShard[shardID]
if !ok {
rewardsPerShard[shardID] = big.NewInt(0)
}

valueBig, okR := rewardsPerShard[shardID].SetString(tx.Value, 10)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
valueBig, okR := rewardsPerShard[shardID].SetString(tx.Value, 10)
valueBig, okR := big.NewInt(0).SetString(tx.Value, 10)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otherwise it will also set rewardsPerShard[shardID]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

require.True(t, okR)
rewardsPerShard[shardID].Add(rewardsPerShard[shardID], valueBig)
}
}
}

}

for shardID, reward := range rewardsPerShard {
fmt.Printf("rewards on shard %d: %s\n", shardID, reward.String())
}

require.True(t, allValuesEqual(rewardsPerShard))
}

func readValidatorsAndOwners(filePath string) (map[string]string, error) {
file, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

var nodesSetup struct {
InitialNodes []struct {
PubKey string `json:"pubkey"`
Address string `json:"address"`
} `json:"initialNodes"`
}

err = json.Unmarshal(file, &nodesSetup)
if err != nil {
return nil, err
}

validators := make(map[string]string)
for _, node := range nodesSetup.InitialNodes {
validators[node.PubKey] = node.Address
}

return validators, nil
}

func allValuesEqual(m map[uint32]*big.Int) bool {
var firstValue *big.Int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use m[0] as expectedValue instead of these 2 variables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored

firstSet := false

for _, v := range m {
if !firstSet {
firstValue = v
firstSet = true
} else if firstValue.Cmp(v) != 0 {
return false
}
}
return true
}
33 changes: 32 additions & 1 deletion node/chainSimulator/chainSimulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/hex"
"errors"
"fmt"

"math/big"
"sync"
"time"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/core/sharding"
"github.com/multiversx/mx-chain-core-go/data/api"
"github.com/multiversx/mx-chain-core-go/data/block"
"github.com/multiversx/mx-chain-core-go/data/endProcess"
"github.com/multiversx/mx-chain-core-go/data/transaction"
crypto "github.com/multiversx/mx-chain-crypto-go"
Expand Down Expand Up @@ -181,6 +183,8 @@ func (s *simulator) createChainHandlers(args ArgsBaseChainSimulator) error {
s.initialWalletKeys = outputConfigs.InitialWallets
s.validatorsPrivateKeys = outputConfigs.ValidatorsPrivateKeys

s.addProofs()

log.Info("running the chain simulator with the following parameters",
"number of shards (including meta)", args.NumOfShards+1,
"round per epoch", outputConfigs.Configs.GeneralConfig.EpochStartConfig.RoundsPerEpoch,
Expand All @@ -192,6 +196,26 @@ func (s *simulator) createChainHandlers(args ArgsBaseChainSimulator) error {
return nil
}

func (s *simulator) addProofs() {
proofs := make([]*block.HeaderProof, 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
proofs := make([]*block.HeaderProof, 0)
proofs := make([]*block.HeaderProof, 0, len(s.nodes))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


for shardID, nodeHandler := range s.nodes {
hash := nodeHandler.GetChainHandler().GetGenesisHeaderHash()
proofs = append(proofs, &block.HeaderProof{
HeaderShardId: shardID,
HeaderHash: hash,
})
}

for _, proof := range proofs {
s.GetNodeHandler(core.MetachainShardId).GetDataComponents().Datapool().Proofs().AddProof(proof)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract s.GetNodeHandler(core.MetachainShardId).GetDataComponents().Datapool().Proofs() outside of the for loop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


if proof.HeaderShardId != core.MetachainShardId {
s.GetNodeHandler(proof.HeaderShardId).GetDataComponents().Datapool().Proofs().AddProof(proof)
}
}
}

func computeStartTimeBaseOnInitialRound(args ArgsChainSimulator) int64 {
return args.GenesisTimestamp + int64(args.RoundDurationInMillis/1000)*args.InitialRound
}
Expand Down Expand Up @@ -313,7 +337,14 @@ func (s *simulator) ForceChangeOfEpoch() error {
epoch := s.nodes[core.MetachainShardId].GetProcessComponents().EpochStartTrigger().Epoch()
s.mutex.Unlock()

return s.GenerateBlocksUntilEpochIsReached(int32(epoch + 1))
err := s.GenerateBlocksUntilEpochIsReached(int32(epoch + 1))
if err != nil {
return err
}

s.incrementRoundOnAllValidators()

return s.allNodesCreateBlocks()
}

func (s *simulator) allNodesCreateBlocks() error {
Expand Down
2 changes: 1 addition & 1 deletion node/chainSimulator/process/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ func createProofForHeader(pubKeyBitmap, signature, headerHash []byte, header dat
HeaderEpoch: header.GetEpoch(),
HeaderNonce: header.GetNonce(),
HeaderShardId: header.GetShardID(),
HeaderRound: header.GetNonce(),
HeaderRound: header.GetRound(),
IsStartOfEpoch: header.IsStartOfEpochBlock(),
}
}
Expand Down
2 changes: 1 addition & 1 deletion process/block/metablock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2263,7 +2263,7 @@ func (mp *metaProcessor) createShardInfo() ([]data.ShardDataHandler, error) {
}

isBlockAfterEquivalentMessagesFlag := !check.IfNil(headerInfo.hdr) &&
mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, headerInfo.hdr.GetEpoch()) && headerInfo.hdr.GetNonce() > 1
mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, headerInfo.hdr.GetEpoch()) && headerInfo.hdr.GetNonce() >= 1
hasMissingShardHdrProof := isBlockAfterEquivalentMessagesFlag && !mp.proofsPool.HasProof(headerInfo.hdr.GetShardID(), []byte(hdrHash))
if hasMissingShardHdrProof {
return nil, fmt.Errorf("%w for shard header with hash %s", process.ErrMissingHeaderProof, hex.EncodeToString([]byte(hdrHash)))
Expand Down