Skip to content

Commit 0a5e94e

Browse files
committed
Merge remote-tracking branch 'upstream/master' into readonlycrosschain
2 parents 30ca9b3 + e9bc306 commit 0a5e94e

7 files changed

Lines changed: 183 additions & 47 deletions

File tree

bcs/consensus/xpoa/common.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package xpoa
33
import (
44
"encoding/json"
55
"errors"
6+
"strconv"
67
)
78

89
var (
@@ -30,7 +31,6 @@ const (
3031
)
3132

3233
type xpoaConfig struct {
33-
Version string `json:"version,omitempty"`
3434
// 每个候选人每轮出块个数
3535
BlockNum int64 `json:"block_num"`
3636
// 单位为毫秒
@@ -103,3 +103,28 @@ func (a aksSlice) Less(i, j int) bool {
103103
}
104104
return a[j].Weight < a[i].Weight
105105
}
106+
107+
type xpoaStringConfig struct {
108+
Version string `json:"version,omitempty"`
109+
}
110+
111+
type xpoaIntConfig struct {
112+
Version int64 `json:"version,omitempty"`
113+
}
114+
115+
// ParseVersion 支持string格式和int格式的version type
116+
func ParseVersion(cfg string) (int64, error) {
117+
intVersion := xpoaIntConfig{}
118+
if err := json.Unmarshal([]byte(cfg), &intVersion); err == nil {
119+
return intVersion.Version, nil
120+
}
121+
strVersion := xpoaStringConfig{}
122+
if err := json.Unmarshal([]byte(cfg), &strVersion); err != nil {
123+
return 0, err
124+
}
125+
version, err := strconv.ParseInt(strVersion.Version, 10, 64)
126+
if err != nil {
127+
return 0, err
128+
}
129+
return version, nil
130+
}

bcs/consensus/xpoa/common_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,40 @@ func TestLoadValidatorsMultiInfo(t *testing.T) {
4242
t.Error("TestLoadValidatorsMultiInfo error 2.")
4343
}
4444
}
45+
46+
func TestParseVersion(t *testing.T) {
47+
strVersion := `{
48+
"version": "2"
49+
}`
50+
v, err := ParseVersion(strVersion)
51+
if err != nil {
52+
t.Error("ParseVersion err, err: ", err)
53+
return
54+
}
55+
if v != 2 {
56+
t.Error("ParseVersion err, v: ", v)
57+
return
58+
}
59+
intVersion := `{
60+
"version": 3
61+
}`
62+
v, err = ParseVersion(intVersion)
63+
if err != nil {
64+
t.Error("ParseVersion err, err: ", err)
65+
return
66+
}
67+
if v != 3 {
68+
t.Error("ParseVersion err, v: ", v)
69+
return
70+
}
71+
empryVersion := `{}`
72+
v, err = ParseVersion(empryVersion)
73+
if err != nil {
74+
t.Error("ParseVersion err, err: ", err)
75+
return
76+
}
77+
if v != 0 {
78+
t.Error("ParseVersion err, v: ", v)
79+
return
80+
}
81+
}

bcs/consensus/xpoa/kernel_contract.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,25 @@ func (x *xpoaConsensus) methodEditValidates(contractCtx contract.KContext) (*con
3333
if err != nil {
3434
return common.NewContractErrResponse(common.StatusBadRequest, "invalid acl: pls check accept value."), err
3535
}
36-
if !x.isAuthAddress(aks, acceptValue) {
36+
37+
curValiBytes, err := contractCtx.Get(x.election.bindContractBucket,
38+
[]byte(fmt.Sprintf("%d_%s", x.election.consensusVersion, validateKeys)))
39+
curVali, err := func() ([]string, error) {
40+
if err != nil || curValiBytes == nil {
41+
return x.election.initValidators, nil
42+
}
43+
var curValiKey ProposerInfo
44+
err = json.Unmarshal(curValiBytes, &curValiKey)
45+
if err != nil {
46+
x.log.Error("Unmarshal error")
47+
return nil, err
48+
}
49+
return curValiKey.Address, nil
50+
}()
51+
if err != nil {
52+
return common.NewContractErrResponse(common.StatusBadRequest, err.Error()), err
53+
}
54+
if !x.isAuthAddress(curVali, aks, acceptValue, x.election.enableBFT) {
3755
return common.NewContractErrResponse(common.StatusBadRequest, aclErr.Error()), aclErr
3856
}
3957

@@ -87,10 +105,18 @@ func (x *xpoaConsensus) methodGetValidates(contractCtx contract.KContext) (*cont
87105
}
88106

89107
// isAuthAddress 判断输入aks是否能在贪心下仍能满足签名数量>33%(Chained-BFT装载) or 50%(一般情况)
90-
func (x *xpoaConsensus) isAuthAddress(aks map[string]float64, threshold float64) bool {
108+
func (x *xpoaConsensus) isAuthAddress(validators []string, aks map[string]float64, threshold float64, enableBFT bool) bool {
109+
// 0. 是否是单个候选人
110+
if len(validators) == 1 {
111+
weight, ok := aks[validators[0]]
112+
if !ok {
113+
return false
114+
}
115+
return weight >= threshold
116+
}
91117
// 1. 判断aks中的地址是否是当前集合地址
92118
for addr, _ := range aks {
93-
if !Find(addr, x.election.validators) {
119+
if !Find(addr, validators) {
94120
return false
95121
}
96122
}
@@ -106,15 +132,14 @@ func (x *xpoaConsensus) isAuthAddress(aks map[string]float64, threshold float64)
106132
greedyCount := 0
107133
sum := threshold
108134
for i := 0; i < len(aks); i++ {
109-
if sum > 0 {
110-
sum -= s[i].Weight
111-
greedyCount++
112-
continue
135+
if sum <= 0 {
136+
break
113137
}
114-
break
138+
sum -= s[i].Weight
139+
greedyCount++
115140
}
116-
if !x.election.enableBFT {
117-
return greedyCount >= len(x.election.validators)/2+1
141+
if !enableBFT {
142+
return greedyCount >= len(validators)/2+1
118143
}
119-
return CalFault(int64(greedyCount), int64(len(x.election.validators)))
144+
return CalFault(int64(greedyCount), int64(len(validators)))
120145
}

bcs/consensus/xpoa/kernel_contract_test.go

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,15 @@ var (
1212
"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN": 0.5,
1313
"WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT": 0.5,
1414
}
15-
)
16-
17-
func TestIsAuthAddress(t *testing.T) {
18-
cCtx, err := prepare(getXpoaConsensusConf())
19-
if err != nil {
20-
t.Error("prepare error", "error", err)
21-
return
22-
}
23-
i := NewXpoaConsensus(*cCtx, getConfig(getXpoaConsensusConf()))
24-
xpoa, ok := i.(*xpoaConsensus)
25-
if !ok {
26-
t.Error("transfer err.")
15+
aks2 = map[string]float64{
16+
"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN": 0.5,
17+
"WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT": 0.6,
2718
}
28-
if !xpoa.isAuthAddress(aks, 0.6) {
29-
t.Error("isAuthAddress err.")
19+
aks3 = map[string]float64{
20+
"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN": 0.4,
21+
"WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT": 0.6,
3022
}
31-
}
23+
)
3224

3325
func NewEditArgs() map[string][]byte {
3426
a := make(map[string][]byte)
@@ -85,3 +77,36 @@ func TestMethodGetValidates(t *testing.T) {
8577
return
8678
}
8779
}
80+
81+
func TestIsAuthAddress(t *testing.T) {
82+
cCtx, err := prepare(getXpoaConsensusConf())
83+
if err != nil {
84+
t.Error("prepare error", "error", err)
85+
return
86+
}
87+
i := NewXpoaConsensus(*cCtx, getConfig(getXpoaConsensusConf()))
88+
xpoa, ok := i.(*xpoaConsensus)
89+
if !ok {
90+
t.Error("transfer err.")
91+
return
92+
}
93+
v1 := []string{"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN", "WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT"}
94+
if !xpoa.isAuthAddress(v1, aks, 0.6, false) {
95+
t.Error("isAuthAddress err.")
96+
return
97+
}
98+
v2 := []string{"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN"}
99+
if xpoa.isAuthAddress(v2, aks2, 0.6, true) {
100+
t.Error("isAuthAddress err.")
101+
return
102+
}
103+
v3 := []string{"WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT"}
104+
if !xpoa.isAuthAddress(v3, aks2, 0.6, true) {
105+
t.Error("isAuthAddress err.")
106+
return
107+
}
108+
v4 := []string{"dpzuVdosQrF2kmzumhVeFQZa1aYcdgFpN", "WNWk3ekXeM5M2232dY2uCJmEqWhfQiDYT"}
109+
if !xpoa.isAuthAddress(v4, aks2, 0.7, true) {
110+
t.Error("isAuthAddress err.")
111+
}
112+
}

bcs/consensus/xpoa/schedule.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package xpoa
22

33
import (
44
"fmt"
5-
"strconv"
65
"time"
76

87
common "github.com/xuperchain/xupercore/kernel/consensus/base/common"
@@ -35,12 +34,7 @@ type xpoaSchedule struct {
3534
ledger cctx.LedgerRely
3635
}
3736

38-
func NewXpoaSchedule(xconfig *xpoaConfig, cCtx context.ConsensusCtx, startHeight int64) *xpoaSchedule {
39-
version, err := strconv.ParseInt(xconfig.Version, 10, 64)
40-
if err != nil {
41-
cCtx.XLog.Error("Xpoa::NewXpoaSchedule::Parse version error.", "err", err)
42-
return nil
43-
}
37+
func NewXpoaSchedule(xconfig *xpoaConfig, cCtx context.ConsensusCtx, startHeight, version int64) *xpoaSchedule {
4438
s := xpoaSchedule{
4539
address: cCtx.Network.PeerInfo().Account,
4640
period: xconfig.Period,

bcs/consensus/xpoa/xpoa.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package xpoa
33
import (
44
"bytes"
55
"encoding/json"
6-
"strconv"
76
"time"
87

98
"github.com/xuperchain/xupercore/kernel/common/xcontext"
@@ -66,17 +65,15 @@ func NewXpoaConsensus(cCtx cctx.ConsensusCtx, cCfg def.ConsensusConfig) base.Con
6665
cCtx.XLog.Error("consensus:xpoa:NewXpoaConsensus: xpoa struct unmarshal error", "error", err)
6766
return nil
6867
}
69-
//兼容老版本配置文件
70-
if len(xconfig.Version) < 1 {
71-
xconfig.Version = "0"
72-
}
73-
version, err := strconv.ParseInt(xconfig.Version, 10, 64)
68+
69+
version, err := ParseVersion(cCfg.Config)
70+
7471
if err != nil {
7572
cCtx.XLog.Error("consensus:xpoa:NewXpoaConsensus: version error", "error", err)
7673
return nil
7774
}
7875
// create xpoaSchedule
79-
schedule := NewXpoaSchedule(xconfig, cCtx, cCfg.StartHeight)
76+
schedule := NewXpoaSchedule(xconfig, cCtx, cCfg.StartHeight, version)
8077
if schedule == nil {
8178
cCtx.XLog.Error("consensus:xpoa:NewXpoaSchedule error")
8279
return nil

kernel/consensus/base/driver/chained-bft/smr.go

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,14 +219,11 @@ func (s *Smr) ResetProposerStatus(tipBlock cctx.BlockInterface,
219219
s.mtx.Lock()
220220
defer s.mtx.Unlock()
221221

222-
if bytes.Equal(s.getHighQC().GetProposalId(), tipBlock.GetBlockid()) {
222+
if bytes.Equal(s.getHighQC().GetProposalId(), tipBlock.GetBlockid()) &&
223+
s.validNewHighQC(tipBlock.GetBlockid(), validators) {
223224
// 此处需要获取带签名的完整Justify
224225
return false, s.getCompleteHighQC(), nil
225226
}
226-
// 单个节点不存在投票验证的hotstuff流程,因此返回true
227-
if len(validators) == 1 {
228-
return false, nil, nil
229-
}
230227

231228
// 从当前TipBlock开始往前追溯,交给smr根据状态进行回滚。
232229
// 在本地状态树上找到指代TipBlock的QC,若找不到,则在状态树上找和TipBlock同一分支上的最近值
@@ -384,10 +381,43 @@ func (s *Smr) ProcessProposal(viewNumber int64, proposalID []byte, parentID []by
384381
}
385382
go s.p2p.SendMessage(createNewBCtx(), netMsg, p2p.WithAccounts(s.removeLocalValidator(validatesIpInfo)))
386383
s.localProposal.Store(utils.F(proposalID), proposal.Timestamp)
387-
s.log.Debug("smr:ProcessProposal::new proposal has been made", "address", s.address, "proposalID", utils.F(proposalID))
384+
// 若为单候选人情况,则此处需要特殊处理,矿工需要给自己提前签名
385+
if len(validatesIpInfo) == 1 {
386+
s.voteToSelf(viewNumber, proposalID, parentQuorumCert)
387+
}
388+
s.log.Debug("smr:ProcessProposal::new proposal has been made", "address", s.address, "proposalID", utils.F(proposalID), "target", validatesIpInfo)
388389
return nil
389390
}
390391

392+
func (s *Smr) voteToSelf(viewNumber int64, proposalID []byte, parent storage.QuorumCertInterface) {
393+
selfVote := &storage.VoteInfo{
394+
ProposalId: proposalID,
395+
ProposalView: viewNumber,
396+
ParentId: parent.GetProposalId(),
397+
}
398+
selfLedgerInfo := &storage.LedgerCommitInfo{
399+
VoteInfoHash: proposalID,
400+
}
401+
selfQC := storage.NewQuorumCert(selfVote, selfLedgerInfo, nil)
402+
selfSign, err := s.cryptoClient.SignVoteMsg(proposalID)
403+
if err != nil {
404+
s.log.Error("smr::voteProposal::voteToSelf error", "err", err)
405+
return
406+
}
407+
s.qcVoteMsgs.LoadOrStore(utils.F(proposalID), []*chainedBftPb.QuorumCertSign{selfSign})
408+
selfNode := &storage.ProposalNode{
409+
In: selfQC,
410+
}
411+
if err := s.qcTree.UpdateQcStatus(selfNode); err != nil {
412+
s.log.Error("smr::voteProposal::updateQcStatus error", "err", err)
413+
return
414+
}
415+
// 更新本地smr状态机
416+
s.pacemaker.AdvanceView(selfQC)
417+
s.qcTree.UpdateHighQC(proposalID)
418+
s.log.Debug("smr:voteProposal::done local voting", "address", s.address, "proposalID", utils.F(proposalID))
419+
}
420+
391421
// reloadJustifyQC 与LibraBFT不同,返回一个指定的parentQC
392422
func (s *Smr) reloadJustifyQC(parentID []byte) (storage.QuorumCertInterface, error) {
393423
// 第一次proposal,highQC==rootQC==genesisQC
@@ -695,6 +725,9 @@ func (s *Smr) validNewHighQC(inProposalId []byte, validators []string) bool {
695725
if !ok {
696726
return false
697727
}
728+
if len(validators) == 1 {
729+
return len(signs) == len(validators)
730+
}
698731
return s.saftyrules.CalVotesThreshold(len(signs), len(validators))
699732
}
700733

0 commit comments

Comments
 (0)