OSDN Git Service

Moidfy api get block (#1932)
[bytom/bytom.git] / protocol / consensus / apply_block.go
1 package consensus
2
3 import (
4         "encoding/hex"
5
6         "github.com/bytom/bytom/errors"
7         "github.com/bytom/bytom/math/checked"
8         "github.com/bytom/bytom/protocol"
9         "github.com/bytom/bytom/protocol/bc"
10         "github.com/bytom/bytom/protocol/bc/types"
11         "github.com/bytom/bytom/protocol/state"
12 )
13
14 // ApplyBlock used to receive a new block from upper layer, it provides idempotence
15 // and parse the vote and mortgage from the transactions, then save to the checkpoint
16 // the tree of checkpoint will grow with the arrival of new blocks
17 // it will return verification when an epoch is reached and the current node is the validator, otherwise return nil
18 // the chain module must broadcast the verification
19 func (c *Casper) ApplyBlock(block *types.Block) (*protocol.Verification, error) {
20         c.mu.Lock()
21         defer c.mu.Unlock()
22
23         if _, err := c.tree.nodeByHash(block.Hash()); err == nil {
24                 // already processed
25                 return nil, nil
26         }
27
28         target, err := c.applyBlockToCheckpoint(block)
29         if err != nil {
30                 return nil, errors.Wrap(err, "apply block to checkpoint")
31         }
32
33         if err := c.applyTransactions(target, block.Transactions); err != nil {
34                 return nil, err
35         }
36
37         validators, err := c.Validators(&target.Hash)
38         if err != nil {
39                 return nil, err
40         }
41
42         if err := c.applySupLinks(target, block.SupLinks, validators); err != nil {
43                 return nil, err
44         }
45
46         if block.Height%state.BlocksOfEpoch == 0 {
47                 c.newEpochCh <- block.Hash()
48         }
49
50         return c.myVerification(target, validators)
51 }
52
53 func (c *Casper) applyBlockToCheckpoint(block *types.Block) (*state.Checkpoint, error) {
54         node, err := c.tree.nodeByHash(block.PreviousBlockHash)
55         if err != nil {
56                 return nil, err
57         }
58
59         checkpoint := node.checkpoint
60         if mod := block.Height % state.BlocksOfEpoch; mod == 1 {
61                 parent := checkpoint
62                 checkpoint = &state.Checkpoint{
63                         ParentHash:     parent.Hash,
64                         Parent:         parent,
65                         StartTimestamp: block.Timestamp,
66                         Status:         state.Growing,
67                         Votes:          make(map[string]uint64),
68                         Guaranties:     make(map[string]uint64),
69                 }
70                 node.children = append(node.children, &treeNode{checkpoint: checkpoint})
71         } else if mod == 0 {
72                 checkpoint.Status = state.Unjustified
73         }
74
75         checkpoint.Height = block.Height
76         checkpoint.Hash = block.Hash()
77         return checkpoint, nil
78 }
79
80 func (c *Casper) applyTransactions(target *state.Checkpoint, transactions []*types.Tx) error {
81         for _, tx := range transactions {
82                 for _, input := range tx.Inputs {
83                         if vetoInput, ok := input.TypedInput.(*types.VetoInput); ok {
84                                 if err := processVeto(vetoInput, target); err != nil {
85                                         return err
86                                 }
87                         }
88
89                         if isGuarantyProgram(input.ControlProgram()) {
90                                 if err := processWithdrawal(decodeGuarantyArgs(input.ControlProgram()), target); err != nil {
91                                         return err
92                                 }
93                         }
94                 }
95
96                 for _, output := range tx.Outputs {
97                         if _, ok := output.TypedOutput.(*types.VoteOutput); ok {
98                                 if err := processVote(output, target); err != nil {
99                                         return err
100                                 }
101                         }
102
103                         if isGuarantyProgram(output.ControlProgram) {
104                                 if err := processGuaranty(decodeGuarantyArgs(output.ControlProgram), target); err != nil {
105                                         return err
106                                 }
107                         }
108                 }
109         }
110         return nil
111 }
112
113 // applySupLinks copy the block's supLink to the checkpoint
114 func (c *Casper) applySupLinks(target *state.Checkpoint, supLinks []*types.SupLink, validators []*state.Validator) error {
115         if target.Height%state.BlocksOfEpoch != 0 {
116                 return nil
117         }
118
119         for _, supLink := range supLinks {
120                 for _, verification := range supLinkToVerifications(supLink, validators, target.Hash, target.Height) {
121                         if err := c.verifyVerification(verification, true); err == nil {
122                                 if err := c.addVerificationToCheckpoint(target, verification); err != nil {
123                                         return err
124                                 }
125                         }
126                 }
127         }
128         return nil
129 }
130
131 func (c *Casper) myVerification(target *state.Checkpoint, validators []*state.Validator) (*protocol.Verification, error) {
132         pubKey := c.prvKey.XPub().String()
133         if !isValidator(pubKey, validators) {
134                 return nil, nil
135         }
136
137         source := c.lastJustifiedCheckpointOfBranch(target)
138         if source != nil {
139                 v := &protocol.Verification{
140                         SourceHash:   source.Hash,
141                         TargetHash:   target.Hash,
142                         SourceHeight: source.Height,
143                         TargetHeight: target.Height,
144                         PubKey:       pubKey,
145                 }
146
147                 if err := v.Sign(c.prvKey); err != nil {
148                         return nil, err
149                 }
150
151                 if err := c.verifyVerification(v, false); err != nil {
152                         return nil, nil
153                 }
154
155                 return v, c.addVerificationToCheckpoint(target, v)
156         }
157         return nil, nil
158 }
159
160 type guarantyArgs struct {
161         Amount uint64
162         PubKey []byte
163 }
164
165 func isGuarantyProgram(program []byte) bool {
166         return false
167 }
168
169 func decodeGuarantyArgs(program []byte) *guarantyArgs {
170         return nil
171 }
172
173 func processWithdrawal(guarantyArgs *guarantyArgs, checkpoint *state.Checkpoint) error {
174         pubKey := hex.EncodeToString(guarantyArgs.PubKey)
175         guarantyNum := checkpoint.Guaranties[pubKey]
176         guarantyNum, ok := checked.SubUint64(guarantyNum, guarantyArgs.Amount)
177         if !ok {
178                 return errOverflow
179         }
180
181         checkpoint.Guaranties[pubKey] = guarantyNum
182         // TODO delete the evil validator when receive the confiscate transaction
183         return nil
184 }
185
186 func processGuaranty(guarantyArgs *guarantyArgs, checkpoint *state.Checkpoint) error {
187         if guarantyArgs.Amount < minGuaranty {
188                 return errGuarantyLessThanMinimum
189         }
190
191         pubKey := hex.EncodeToString(guarantyArgs.PubKey)
192         guarantyNum := checkpoint.Guaranties[pubKey]
193         guarantyNum, ok := checked.AddUint64(guarantyNum, guarantyArgs.Amount)
194         if !ok {
195                 return errOverflow
196         }
197
198         checkpoint.Guaranties[pubKey] = guarantyNum
199         return nil
200 }
201
202 func processVeto(input *types.VetoInput, checkpoint *state.Checkpoint) error {
203         pubKey := hex.EncodeToString(input.Vote)
204         voteNum := checkpoint.Votes[pubKey]
205         voteNum, ok := checked.SubUint64(voteNum, input.Amount)
206         if !ok {
207                 return errOverflow
208         }
209
210         checkpoint.Votes[pubKey] = voteNum
211         return nil
212 }
213
214 func processVote(output *types.TxOutput, checkpoint *state.Checkpoint) error {
215         voteOutput := output.TypedOutput.(*types.VoteOutput)
216         pubKey := hex.EncodeToString(voteOutput.Vote)
217         if checkpoint.Guaranties[pubKey] < minGuaranty {
218                 return errVoteToNonValidator
219         }
220
221         voteNum := checkpoint.Votes[pubKey]
222         voteNum, ok := checked.AddUint64(voteNum, output.Amount)
223         if !ok {
224                 return errOverflow
225         }
226
227         checkpoint.Votes[pubKey] = voteNum
228         return nil
229 }
230
231 func (c *Casper) lastJustifiedCheckpointOfBranch(branch *state.Checkpoint) *state.Checkpoint {
232         parent := branch.Parent
233         for parent != nil {
234                 switch parent.Status {
235                 case state.Finalized:
236                         return nil
237                 case state.Justified:
238                         return parent
239                 }
240         }
241         return nil
242 }
243
244 func supLinkToVerifications(supLink *types.SupLink, validators []*state.Validator, targetHash bc.Hash, targetHeight uint64) []*protocol.Verification {
245         var result []*protocol.Verification
246         for i, signature := range supLink.Signatures {
247                 result = append(result, &protocol.Verification{
248                         SourceHash:   supLink.SourceHash,
249                         TargetHash:   targetHash,
250                         SourceHeight: supLink.SourceHeight,
251                         TargetHeight: targetHeight,
252                         Signature:    hex.EncodeToString(signature),
253                         PubKey:       validators[i].PubKey,
254                 })
255         }
256         return result
257 }