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 TIP2019Block = big.NewInt(1050000)
var TIPSigning = big.NewInt(3000000) var TIPSigning = big.NewInt(3000000)
var TIPRandomize = big.NewInt(3410000)
var IsTestnet bool = false var IsTestnet bool = false
var StoreRewardFolder string var StoreRewardFolder string
var RollbackHash Hash var RollbackHash Hash

View file

@ -225,8 +225,8 @@ type Posv struct {
signFn clique.SignerFn // Signer function to authorize hashes with signFn clique.SignerFn // Signer function to authorize hashes with
lock sync.RWMutex // Protects the signer fields lock sync.RWMutex // Protects the signer fields
BlockSigners *lru.Cache 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) HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error)
HookPenaltyTIPSigning func(chain consensus.ChainReader, header *types.Header, candidate []common.Address) ([]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) 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") return common.Address{}, fmt.Errorf("couldn't find checkpoint header")
} }
} }
m, err := GetM1M2FromCheckpointHeader(cpHeader) m, err := GetM1M2FromCheckpointHeader(cpHeader, header, chain.Config())
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
@ -1125,26 +1125,41 @@ func GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common
} }
// Get m2 list from checkpoint block. // 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 { if checkpointHeader.Number.Uint64()%common.EpocBlockRandomize != 0 {
return nil, errors.New("This block is not checkpoint block epoc.") return nil, errors.New("This block is not checkpoint block epoc.")
} }
m1m2 := map[common.Address]common.Address{}
// Get signers from this block. // Get signers from this block.
masternodes := GetMasternodesFromCheckpointHeader(checkpointHeader) masternodes := GetMasternodesFromCheckpointHeader(checkpointHeader)
validators := ExtractValidatorsFromBytes(checkpointHeader.Validators) validators := ExtractValidatorsFromBytes(checkpointHeader.Validators)
m1m2, _, err := getM1M2(masternodes, validators, currentHeader, config)
if len(validators) < len(masternodes) { if err != nil {
return nil, errors.New("len(m2) is less than len(m1)") return map[common.Address]common.Address{}, err
}
if len(masternodes) > 0 {
for i, m1 := range masternodes {
m1m2[m1] = masternodes[validators[i]%int64(len(masternodes))]
}
} }
return m1m2, nil 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. // Extract validators from byte array.
func ExtractValidatorsFromBytes(byteValidators []byte) []int64 { func ExtractValidatorsFromBytes(byteValidators []byte) []int64 {
lenValidator := len(byteValidators) / M2ByteLength 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) { c.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
prevEpoc := header.Number.Uint64() - chain.Config().Posv.Epoch prevEpoc := header.Number.Uint64() - chain.Config().Posv.Epoch
combackEpoch := uint64(0) 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 { if header.Number.Uint64() > comebackLength {
combackEpoch = 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) penalties = append(penalties, addr)
} }
} }
// get list check penalties signing block & list master nodes wil comeback // get list check penalties signing block & list master nodes wil comeback
penComebacks := []common.Address{} penComebacks := []common.Address{}
if combackEpoch > 0 { 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))) 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...) penalties = append(penalties, penComebacks...)
return penalties, nil if chain.Config().IsTIPRandomize(header.Number) {
return penalties, nil
}
return penComebacks, nil
} }
return []common.Address{}, nil return []common.Address{}, nil
} }

View file

@ -27,6 +27,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/accounts" "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/accounts/keystore"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "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/ethash"
"github.com/ethereum/go-ethereum/consensus/posv" "github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/contracts" "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"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -45,17 +47,14 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/util" "github.com/syndtr/goleveldb/leveldb/util"
contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
) )
const ( const (
defaultGasPrice = 50 * params.Shannon defaultGasPrice = 50 * params.Shannon
// statuses of candidates // statuses of candidates
statusMasternode = "MASTERNODE" statusMasternode = "MASTERNODE"
statusSlashed = "SLASHED" statusSlashed = "SLASHED"
statusProposed = "PROPOSED" statusProposed = "PROPOSED"
) )
// PublicEthereumAPI provides an API to access Ethereum related information. // 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 return masternodes, nil
} }
// GetCandidateStatus returns status of the given candidate at a specified epochNumber // 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) { func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAddress common.Address, epochNumber rpc.EpochNumber) (string, error) {
var ( var (
block *types.Block block *types.Block
masternodes, penaltyList []common.Address masternodes, penaltyList []common.Address
penalties []byte penalties []byte
err error err error
) )
block = s.b.CurrentBlock() block = s.b.CurrentBlock()
epoch := s.b.ChainConfig().Posv.Epoch epoch := s.b.ChainConfig().Posv.Epoch
@ -749,7 +747,7 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd
opts := new(bind.CallOpts) opts := new(bind.CallOpts)
var ( var (
candidateAddresses []common.Address candidateAddresses []common.Address
candidates []posv.Masternode candidates []posv.Masternode
) )
candidateAddresses, err = validator.GetCandidates(opts) candidateAddresses, err = validator.GetCandidates(opts)
@ -780,12 +778,12 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd
break break
} }
} }
if isTopCandidate == false { if !isTopCandidate {
return status, nil return status, nil
} }
// look up recent checkpoint headers to get penalty list // look up recent checkpoint headers to get penalty list
for i := 0; i <= common.LimitPenaltyEpoch; i++ { 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)) blockCheckpointNumber := rpc.BlockNumber(blockNum - (blockNum % epoch) - (uint64(i) * epoch))
blockCheckpoint, err := s.b.BlockByNumber(ctx, blockCheckpointNumber) blockCheckpoint, err := s.b.BlockByNumber(ctx, blockCheckpointNumber)
if err != nil { if err != nil {

View file

@ -221,6 +221,10 @@ func (c *ChainConfig) IsTIPSigning(num *big.Int) bool {
return isForked(common.TIPSigning, num) 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). // 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. // The returned GasTable's fields shouldn't, under any circumstances, be changed.

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 3 // Minor 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 VersionMeta = "stable" // Version metadata to append to the version string
) )

View file

@ -123,7 +123,7 @@ const (
PendingBlockNumber = BlockNumber(-2) PendingBlockNumber = BlockNumber(-2)
LatestBlockNumber = BlockNumber(-1) LatestBlockNumber = BlockNumber(-1)
EarliestBlockNumber = BlockNumber(0) EarliestBlockNumber = BlockNumber(0)
LatestEpochNumber = EpochNumber(-1) LatestEpochNumber = EpochNumber(-1)
) )
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: