diff --git a/common/constants.go b/common/constants.go index 7c66a44368..8af9b17ebe 100644 --- a/common/constants.go +++ b/common/constants.go @@ -24,6 +24,7 @@ const ( var TIP2019Block = big.NewInt(1050000) var TIPSigning = big.NewInt(3000000) +var TIPRandomize = big.NewInt(901) var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a96bc2e10a..e14e961dc3 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -226,7 +226,7 @@ type Posv struct { lock sync.RWMutex // Protects the signer fields BlockSigners *lru.Cache - HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) + HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) HookPenaltyTIPSigning func(chain consensus.ChainReader, header *types.Header, candidate []common.Address) ([]common.Address, error) HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) @@ -739,7 +739,7 @@ func (c *Posv) GetValidator(creator common.Address, chain consensus.ChainReader, return common.Address{}, fmt.Errorf("couldn't find checkpoint header") } } - m, err := GetM1M2FromCheckpointHeader(cpHeader) + m, err := GetM1M2FromCheckpointHeader(cpHeader, header, chain.Config()) if err != nil { return common.Address{}, err } @@ -1125,7 +1125,7 @@ func GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common } // Get m2 list from checkpoint block. -func GetM1M2FromCheckpointHeader(checkpointHeader *types.Header) (map[common.Address]common.Address, error) { +func GetM1M2FromCheckpointHeader(checkpointHeader *types.Header, currentHeader *types.Header, config *params.ChainConfig) (map[common.Address]common.Address, error) { if checkpointHeader.Number.Uint64()%common.EpocBlockRandomize != 0 { return nil, errors.New("This block is not checkpoint block epoc.") } @@ -1134,12 +1134,23 @@ func GetM1M2FromCheckpointHeader(checkpointHeader *types.Header) (map[common.Add masternodes := GetMasternodesFromCheckpointHeader(checkpointHeader) validators := ExtractValidatorsFromBytes(checkpointHeader.Validators) - if len(validators) < len(masternodes) { + maxMNs := len(masternodes) + if len(validators) < maxMNs { return nil, errors.New("len(m2) is less than len(m1)") } - if len(masternodes) > 0 { + if maxMNs > 0 { + isForked := config.IsTIPRandomize(currentHeader.Number) + moveM2 := uint64(0) + if isForked { + moveM2 = (currentHeader.Number.Uint64() % config.Posv.Epoch) / uint64(maxMNs) + } for i, m1 := range masternodes { - m1m2[m1] = masternodes[validators[i]%int64(len(masternodes))] + m2Index := uint64(validators[i] % int64(maxMNs)) + m2Index = m2Index + moveM2 + if m2Index >= common.MaxMasternodes { + m2Index = m2Index - common.MaxMasternodes + } + m1m2[m1] = masternodes[m2Index] } } return m1m2, nil diff --git a/eth/backend.go b/eth/backend.go index 94321a8962..3d2545d376 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -322,7 +322,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { c.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) { prevEpoc := header.Number.Uint64() - chain.Config().Posv.Epoch combackEpoch := uint64(0) - comebackLength := uint64((common.LimitPenaltyEpoch + 1) * chain.Config().Posv.Epoch) + comebackLength := (common.LimitPenaltyEpoch + 1) * chain.Config().Posv.Epoch if header.Number.Uint64() > comebackLength { combackEpoch = header.Number.Uint64() - comebackLength } @@ -367,7 +367,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { penalties = append(penalties, addr) } } - + // get list check penalties signing block & list master nodes wil comeback penComebacks := []common.Address{} if combackEpoch > 0 { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 16979dfe4e..5dbd1f90df 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -27,6 +27,7 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -34,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/posv" "github.com/ethereum/go-ethereum/contracts" + contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -45,17 +47,14 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" - contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract" - "github.com/ethereum/go-ethereum/accounts/abi/bind" ) const ( - defaultGasPrice = 50 * params.Shannon + defaultGasPrice = 50 * params.Shannon // statuses of candidates - statusMasternode = "MASTERNODE" - statusSlashed = "SLASHED" - statusProposed = "PROPOSED" - + statusMasternode = "MASTERNODE" + statusSlashed = "SLASHED" + statusProposed = "PROPOSED" ) // PublicEthereumAPI provides an API to access Ethereum related information. @@ -700,14 +699,13 @@ func (s *PublicBlockChainAPI) GetMasternodes(ctx context.Context, b *types.Block return masternodes, nil } - // GetCandidateStatus returns status of the given candidate at a specified epochNumber func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAddress common.Address, epochNumber rpc.EpochNumber) (string, error) { var ( - block *types.Block + block *types.Block masternodes, penaltyList []common.Address - penalties []byte - err error + penalties []byte + err error ) block = s.b.CurrentBlock() epoch := s.b.ChainConfig().Posv.Epoch @@ -749,7 +747,7 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd opts := new(bind.CallOpts) var ( candidateAddresses []common.Address - candidates []posv.Masternode + candidates []posv.Masternode ) candidateAddresses, err = validator.GetCandidates(opts) @@ -780,12 +778,12 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd break } } - if isTopCandidate == false { + if !isTopCandidate { return status, nil } // look up recent checkpoint headers to get penalty list for i := 0; i <= common.LimitPenaltyEpoch; i++ { - if blockNum > uint64(i) * epoch { + if blockNum > uint64(i)*epoch { blockCheckpointNumber := rpc.BlockNumber(blockNum - (blockNum % epoch) - (uint64(i) * epoch)) blockCheckpoint, err := s.b.BlockByNumber(ctx, blockCheckpointNumber) if err != nil { diff --git a/params/config.go b/params/config.go index 2d275c61f7..8135eb1e14 100644 --- a/params/config.go +++ b/params/config.go @@ -221,6 +221,10 @@ func (c *ChainConfig) IsTIPSigning(num *big.Int) bool { return isForked(common.TIPSigning, num) } +func (c *ChainConfig) IsTIPRandomize(num *big.Int) bool { + return isForked(common.TIPRandomize, num) +} + // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // // The returned GasTable's fields shouldn't, under any circumstances, be changed. diff --git a/rpc/types.go b/rpc/types.go index c456f45d89..25d5a1ca0b 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -123,7 +123,7 @@ const ( PendingBlockNumber = BlockNumber(-2) LatestBlockNumber = BlockNumber(-1) EarliestBlockNumber = BlockNumber(0) - LatestEpochNumber = EpochNumber(-1) + LatestEpochNumber = EpochNumber(-1) ) // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: