/
block.go
153 lines (133 loc) · 4.1 KB
/
block.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pbft
import (
"time"
"github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/queue"
drivers "github.com/33cn/chain33/system/consensus"
cty "github.com/33cn/chain33/system/dapp/coins/types"
"github.com/33cn/chain33/types"
)
func init() {
drivers.Reg("pbft", NewPbft)
drivers.QueryData.Register("pbft", &Client{})
}
// Client Pbft implementation
type Client struct {
*drivers.BaseClient
replyChan chan *types.ClientReply
requestChan chan *types.Request
isPrimary bool
}
// NewBlockstore create Pbft Client
func NewBlockstore(cfg *types.Consensus, replyChan chan *types.ClientReply, requestChan chan *types.Request, isPrimary bool) *Client {
c := drivers.NewBaseClient(cfg)
client := &Client{BaseClient: c, replyChan: replyChan, requestChan: requestChan, isPrimary: isPrimary}
c.SetChild(client)
return client
}
// ProcEvent method
func (client *Client) ProcEvent(msg *queue.Message) bool {
return false
}
// Propose method
func (client *Client) Propose(block *types.Block) {
op := &types.Operation{Value: block}
req := ToRequestClient(op, types.Now().String(), clientAddr)
client.requestChan <- req
}
// CheckBlock method
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
return nil
}
// SetQueueClient method
func (client *Client) SetQueueClient(c queue.Client) {
plog.Info("Enter SetQueue method of pbft consensus")
client.InitClient(c, func() {
client.InitBlock()
})
go client.EventLoop()
//go client.readReply()
go client.CreateBlock()
}
// CreateBlock method
func (client *Client) CreateBlock() {
issleep := true
if !client.isPrimary {
return
}
cfg := client.GetQueueClient().GetConfig()
for {
if issleep {
time.Sleep(10 * time.Second)
}
plog.Info("=============start get tx===============")
lastBlock := client.GetCurrentBlock()
txs := client.RequestTx(int(cfg.GetP(lastBlock.Height+1).MaxTxNumber), nil)
if len(txs) == 0 {
issleep = true
continue
}
issleep = false
plog.Info("==================start create new block!=====================")
//check dup
//txs = client.CheckTxDup(txs)
//fmt.Println(len(txs))
var newblock types.Block
newblock.ParentHash = lastBlock.Hash(cfg)
newblock.Height = lastBlock.Height + 1
newblock.Txs = txs
//需要首先对交易进行排序
if cfg.IsFork(newblock.Height, "ForkRootHash") {
newblock.Txs = types.TransactionSort(newblock.Txs)
}
newblock.TxHash = merkle.CalcMerkleRoot(cfg, newblock.Height, newblock.Txs)
newblock.BlockTime = types.Now().Unix()
if lastBlock.BlockTime >= newblock.BlockTime {
newblock.BlockTime = lastBlock.BlockTime + 1
}
client.Propose(&newblock)
//time.Sleep(time.Second)
client.readReply()
plog.Info("===============readreply and writeblock done===============")
}
}
// GetGenesisBlockTime get genesis blocktime
func (client *Client) GetGenesisBlockTime() int64 {
return genesisBlockTime
}
// CreateGenesisTx get genesis tx
func (client *Client) CreateGenesisTx() (ret []*types.Transaction) {
var tx types.Transaction
tx.Execer = []byte(client.GetAPI().GetConfig().GetCoinExec())
tx.To = genesis
//gen payload
g := &cty.CoinsAction_Genesis{}
g.Genesis = &types.AssetsGenesis{}
g.Genesis.Amount = 1e8 * client.GetAPI().GetConfig().GetCoinPrecision()
tx.Payload = types.Encode(&cty.CoinsAction{Value: g, Ty: cty.CoinsActionGenesis})
ret = append(ret, &tx)
return
}
func (client *Client) readReply() {
data := <-client.replyChan
if data == nil {
plog.Error("block is nil")
return
}
plog.Info("===============Get block from reply channel===========")
//client.SetCurrentBlock(data.Result.Value)
lastBlock := client.GetCurrentBlock()
err := client.WriteBlock(lastBlock.StateHash, data.Result.Value)
if err != nil {
plog.Error("********************err:", err)
return
}
client.SetCurrentBlock(data.Result.Value)
}
//CmpBestBlock 比较newBlock是不是最优区块
func (client *Client) CmpBestBlock(newBlock *types.Block, cmpBlock *types.Block) bool {
return false
}