From 8a282380082395bb584acd35747587f921149059 Mon Sep 17 00:00:00 2001 From: DinhLN Date: Fri, 22 Mar 2019 10:00:57 +0700 Subject: [PATCH 1/6] Fixed randomize for prevent case m2 down affect to m1. --- common/constants.go | 1 + consensus/posv/posv.go | 23 +++++++++++++++++------ eth/backend.go | 4 ++-- internal/ethapi/api.go | 26 ++++++++++++-------------- params/config.go | 4 ++++ rpc/types.go | 2 +- 6 files changed, 37 insertions(+), 23 deletions(-) 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: From 3e47d28cce51709280b79039576ffc5e6d260969 Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 22 Mar 2019 14:51:09 +0700 Subject: [PATCH 2/6] move unit-test to posv --- consensus/posv/posv.go | 24 +++++++++++-------- consensus/posv/posv_test.go | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 consensus/posv/posv_test.go diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index e14e961dc3..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) @@ -1129,31 +1129,35 @@ func GetM1M2FromCheckpointHeader(checkpointHeader *types.Header, currentHeader * 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) + 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, errors.New("len(m2) is less than len(m1)") + return nil, moveM2, errors.New("len(m2) is less than len(m1)") } 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 { m2Index := uint64(validators[i] % int64(maxMNs)) - m2Index = m2Index + moveM2 - if m2Index >= common.MaxMasternodes { - m2Index = m2Index - common.MaxMasternodes - } + m2Index = (m2Index + moveM2) % uint64(maxMNs) m1m2[m1] = masternodes[m2Index] } } - return m1m2, nil + return m1m2, moveM2, nil } // Extract validators from byte array. 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) + } + } +} From db5ae2e86ed59306d3e023985dc1c52c442383da Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 22 Mar 2019 15:39:32 +0700 Subject: [PATCH 3/6] return penalties at randomize tip fork --- eth/backend.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 3d2545d376..d48323eed2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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 } From 87463cd18338aaac913f55a75e1faeb136d536ff Mon Sep 17 00:00:00 2001 From: Tuna Date: Fri, 22 Mar 2019 15:44:24 +0700 Subject: [PATCH 4/6] set randomize tip block to 3374780 --- common/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/constants.go b/common/constants.go index 8af9b17ebe..a116df5411 100644 --- a/common/constants.go +++ b/common/constants.go @@ -24,7 +24,7 @@ const ( var TIP2019Block = big.NewInt(1050000) var TIPSigning = big.NewInt(3000000) -var TIPRandomize = big.NewInt(901) +var TIPRandomize = big.NewInt(3374780) var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash From 8dee839e43c2f03778b25c060015fc061d1e02f0 Mon Sep 17 00:00:00 2001 From: Tuna Date: Mon, 25 Mar 2019 15:36:41 +0700 Subject: [PATCH 5/6] set TIP random to 3410000 --- common/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/constants.go b/common/constants.go index a116df5411..23bfb4f709 100644 --- a/common/constants.go +++ b/common/constants.go @@ -24,7 +24,7 @@ const ( var TIP2019Block = big.NewInt(1050000) var TIPSigning = big.NewInt(3000000) -var TIPRandomize = big.NewInt(3374780) +var TIPRandomize = big.NewInt(3410000) var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash From 9b0a357a3858dcb481c4b58a6d340fbd2467f5e3 Mon Sep 17 00:00:00 2001 From: Tuna Date: Mon, 25 Mar 2019 15:37:40 +0700 Subject: [PATCH 6/6] set version to v1.3.2 --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 )