diff --git a/common/constants.go b/common/constants.go index 7c66a44368..23bfb4f709 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(3410000) var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index a96bc2e10a..94e84ffb93 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -225,8 +225,8 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with 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{}) + BlockSigners *lru.Cache + 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,26 +1125,41 @@ 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.") } - m1m2 := map[common.Address]common.Address{} // Get signers from this block. masternodes := GetMasternodesFromCheckpointHeader(checkpointHeader) validators := ExtractValidatorsFromBytes(checkpointHeader.Validators) - - if len(validators) < len(masternodes) { - return nil, errors.New("len(m2) is less than len(m1)") - } - if len(masternodes) > 0 { - for i, m1 := range masternodes { - m1m2[m1] = masternodes[validators[i]%int64(len(masternodes))] - } + m1m2, _, err := getM1M2(masternodes, validators, currentHeader, config) + if err != nil { + return map[common.Address]common.Address{}, err } return m1m2, nil } +func getM1M2(masternodes []common.Address, validators []int64, currentHeader *types.Header, config *params.ChainConfig) (map[common.Address]common.Address, uint64, error) { + m1m2 := map[common.Address]common.Address{} + maxMNs := len(masternodes) + moveM2 := uint64(0) + if len(validators) < maxMNs { + return nil, moveM2, errors.New("len(m2) is less than len(m1)") + } + if maxMNs > 0 { + isForked := config.IsTIPRandomize(currentHeader.Number) + if isForked { + moveM2 = (currentHeader.Number.Uint64() % config.Posv.Epoch) / uint64(maxMNs) + } + for i, m1 := range masternodes { + m2Index := uint64(validators[i] % int64(maxMNs)) + m2Index = (m2Index + moveM2) % uint64(maxMNs) + m1m2[m1] = masternodes[m2Index] + } + } + return m1m2, moveM2, nil +} + // Extract validators from byte array. func ExtractValidatorsFromBytes(byteValidators []byte) []int64 { lenValidator := len(byteValidators) / M2ByteLength diff --git a/consensus/posv/posv_test.go b/consensus/posv/posv_test.go new file mode 100644 index 0000000000..c34150de96 --- /dev/null +++ b/consensus/posv/posv_test.go @@ -0,0 +1,47 @@ +package posv + +import ( + "testing" + "math/big" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +func TestGetM1M2FromCheckpointHeader(t *testing.T) { + masternodes := []common.Address{ + common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"), + } + validators := []int64{ + 2, + 1, + 0, + } + epoch := int64(900) + config := ¶ms.ChainConfig{ + Posv: ¶ms.PosvConfig{ + Epoch: uint64(epoch), + }, + } + //try from block 900 to 909 + for i:=int64(0); i<9; i++ { + currentHeader := &types.Header{ + Number: big.NewInt(epoch+i), + } + m1m2, moveM2, err := getM1M2(masternodes, validators, currentHeader, config) + if err != nil { + t.Error("can't get m1m2", "err", err) + } + fmt.Printf("block: %v, moveM2: %v\n", currentHeader.Number.Int64(), moveM2) + for _,k := range masternodes { + fmt.Printf("m1: %v - m2: %v\n", k.Str(), m1m2[k].Str()) + } + if moveM2 != uint64(i/3) { //3 = len(masternodes) + t.Error("wrong moveM2", "want", uint64(i/3), "have", moveM2) + } + } +} diff --git a/eth/backend.go b/eth/backend.go index 94321a8962..d48323eed2 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 { @@ -419,8 +419,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start))) penalties = append(penalties, penComebacks...) - return penalties, nil - + if chain.Config().IsTIPRandomize(header.Number) { + return penalties, nil + } + return penComebacks, nil } return []common.Address{}, nil } 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/params/version.go b/params/version.go index 2f02070a99..3e6810fae8 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 3 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release + VersionPatch = 2 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string ) 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: