Merge pull request #474 from dinhln89/randomize

Fixed randomize for prevent case m2 down affect to m1.
This commit is contained in:
Tuna 2019-03-25 15:41:38 +07:00 committed by GitHub
commit 76708d894e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 100 additions and 33 deletions

View file

@ -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

View file

@ -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

View file

@ -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 := &params.ChainConfig{
Posv: &params.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)
}
}
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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.

View file

@ -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
)

View file

@ -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: