@@ -2,47 +2,52 @@ package main
2
2
3
3
import (
4
4
"bytes"
5
- "fmt"
6
- "github.com/pkg/errors"
5
+ "errors"
7
6
"github.com/tinychain/algorand/common"
8
7
"gonum.org/v1/gonum/stat/distuv"
9
8
"math/big"
10
- "sync/atomic"
11
9
"time"
12
10
)
13
11
14
12
var (
13
+ log = common .GetLogger ("algorand" )
14
+
15
15
errCountVotesTimeout = errors .New ("count votes timeout" )
16
16
)
17
17
18
18
type PID int
19
19
20
20
type Algorand struct {
21
21
id PID
22
- pubkey atomic.Value
23
22
privkey * PrivateKey
23
+ pubkey * PublicKey
24
24
25
25
chain * Blockchain
26
26
peer * Peer
27
27
quitCh chan struct {}
28
28
}
29
29
30
30
func NewAlgorand (id PID ) * Algorand {
31
+ pub , priv , _ := NewKeyPair ()
31
32
alg := & Algorand {
32
- id : id ,
33
- chain : newBlockchain (),
33
+ id : id ,
34
+ privkey : priv ,
35
+ pubkey : pub ,
36
+ chain : newBlockchain (),
34
37
}
35
38
alg .peer = newPeer (alg )
36
39
return alg
37
40
}
38
41
39
42
func (alg * Algorand ) start () {
40
43
alg .quitCh = make (chan struct {})
44
+ GetPeerPool ().add (alg .peer )
41
45
go alg .run ()
42
46
}
43
47
44
48
func (alg * Algorand ) stop () {
45
49
close (alg .quitCh )
50
+ GetPeerPool ().remove (alg .peer )
46
51
}
47
52
48
53
// round returns the latest round number.
@@ -65,21 +70,20 @@ func (alg *Algorand) tokenOwn() uint64 {
65
70
}
66
71
67
72
// seed returns the vrf-based seed of block r.
68
- func (alg * Algorand ) vrfSeed (round uint64 ) (seed , proof []byte ) {
73
+ func (alg * Algorand ) vrfSeed (round uint64 ) (seed , proof []byte , err error ) {
69
74
if round == 0 {
70
- return alg .chain .genesis .Seed , nil
75
+ return alg .chain .genesis .Seed , nil , nil
71
76
}
72
77
lastBlock := alg .chain .getByRound (round - 1 )
73
78
// last block is not genesis, verify the seed r-1.
74
79
if round != 1 {
75
- var err error
76
80
lastParentBlock := alg .chain .get (lastBlock .ParentHash , lastBlock .Round - 1 )
77
81
if lastBlock .Proof != nil {
78
82
// vrf-based seed
79
83
pubkey := recoverPubkey (lastBlock .Signature )
80
84
m := bytes .Join ([][]byte {lastParentBlock .Seed , common .Uint2Bytes (lastBlock .Round )}, nil )
81
85
82
- err = pubkey .VerifyVRF (lastBlock .Seed , lastBlock . Proof , m )
86
+ err = pubkey .VerifyVRF (lastBlock .Proof , m )
83
87
} else if bytes .Compare (lastBlock .Seed , common .Sha256 (
84
88
bytes .Join ([][]byte {
85
89
lastParentBlock .Seed ,
@@ -90,11 +94,11 @@ func (alg *Algorand) vrfSeed(round uint64) (seed, proof []byte) {
90
94
}
91
95
if err != nil {
92
96
// seed r-1 invalid
93
- return common .Sha256 (bytes .Join ([][]byte {lastBlock .Seed , common .Uint2Bytes (lastBlock .Round + 1 )}, nil )).Bytes (), nil
97
+ return common .Sha256 (bytes .Join ([][]byte {lastBlock .Seed , common .Uint2Bytes (lastBlock .Round + 1 )}, nil )).Bytes (), nil , nil
94
98
}
95
99
}
96
100
97
- seed , proof = alg .privkey .Evaluate (bytes .Join ([][]byte {lastBlock .Seed , common .Uint2Bytes (lastBlock .Round + 1 )}, nil ))
101
+ seed , proof , err = alg .privkey .Evaluate (bytes .Join ([][]byte {lastBlock .Seed , common .Uint2Bytes (lastBlock .Round + 1 )}, nil ))
98
102
return
99
103
}
100
104
@@ -111,17 +115,8 @@ func (alg *Algorand) sortitionSeed(round uint64) []byte {
111
115
return alg .chain .getByRound (realR ).Seed
112
116
}
113
117
114
- func (alg * Algorand ) publicKey () * PublicKey {
115
- if pub := alg .pubkey .Load (); pub != nil {
116
- return pub .(* PublicKey )
117
- }
118
- pubkey := alg .privkey .PublicKey ()
119
- alg .pubkey .Store (pubkey )
120
- return pubkey
121
- }
122
-
123
118
func (alg * Algorand ) Address () common.Address {
124
- return common .BytesToAddress (alg .publicKey () .Bytes ())
119
+ return common .BytesToAddress (alg .pubkey .Bytes ())
125
120
}
126
121
127
122
// run performs the all procedures of Algorand algorithm in infinite loop.
@@ -146,14 +141,16 @@ func (alg *Algorand) run() {
146
141
// processMain performs the main processing of algorand algorithm.
147
142
func (alg * Algorand ) processMain () {
148
143
currRound := alg .round () + 1
144
+ log .Infof ("node %d begin to perform consensus at round %d" , alg .id , currRound )
149
145
// 1. block proposal
150
146
block := alg .blockProposal (false )
147
+ log .Debugf ("node %d init BA with block #%d %s" , alg .id , block .Round , block .Hash ())
151
148
152
149
// 2. init BA with block with the highest priority.
153
150
consensusType , block := alg .BA (currRound , block )
154
151
155
152
// 3. reach consensus on a FINAL or TENTATIVE new block.
156
- fmt . Printf ( " reach consensus %d at round %d, block hash %s" , consensusType , currRound , block .Hash ())
153
+ log . Infof ( "node %d reach consensus %d at round %d, block hash %s", alg . id , consensusType , currRound , block .Hash ())
157
154
158
155
// 4. append to the chain.
159
156
alg .chain .add (block )
@@ -175,12 +172,15 @@ func (alg *Algorand) processForkResolve() {
175
172
func (alg * Algorand ) proposeBlock () * Block {
176
173
currRound := alg .round () + 1
177
174
178
- seed , proof := alg .vrfSeed (currRound )
175
+ seed , proof , err := alg .vrfSeed (currRound )
176
+ if err != nil {
177
+ return nil
178
+ }
179
179
blk := & Block {
180
180
Round : currRound ,
181
181
Seed : seed ,
182
182
ParentHash : alg .lastBlock ().Hash (),
183
- Author : alg .publicKey () .Address (),
183
+ Author : alg .pubkey .Address (),
184
184
Time : time .Now ().Unix (),
185
185
Proof : proof ,
186
186
}
@@ -211,6 +211,7 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
211
211
vrf , proof , subusers := alg .sortition (alg .sortitionSeed (round ), role (iden , round , PROPOSE ), expectedBlockProposers , alg .tokenOwn ())
212
212
// have been selected.
213
213
if subusers > 0 {
214
+ log .Debugf ("node %d has %d sub-users selected as block proposer" , alg .id , subusers )
214
215
var (
215
216
newBlk * Block
216
217
proposalType int
@@ -222,13 +223,19 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
222
223
newBlk = alg .proposeFork ()
223
224
proposalType = FORK_PROPOSAL
224
225
}
226
+ if newBlk == nil {
227
+ return & Block {
228
+ Round : round ,
229
+ ParentHash : alg .lastBlock ().Hash (),
230
+ }
231
+ }
225
232
proposal := & Proposal {
226
233
Round : newBlk .Round ,
227
234
Hash : newBlk .Hash (),
228
235
Prior : maxPriority (vrf , subusers ),
229
236
VRF : vrf ,
230
237
Proof : proof ,
231
- Pubkey : alg .publicKey () .Bytes (),
238
+ Pubkey : alg .pubkey .Bytes (),
232
239
}
233
240
alg .peer .setMaxProposal (round , proposal )
234
241
blkMsg , _ := newBlk .Serialize ()
@@ -264,14 +271,14 @@ func (alg *Algorand) blockProposal(resolveFork bool) *Block {
264
271
265
272
// sortition runs cryptographic selection procedure and returns vrf,proof and amount of selected sub-users.
266
273
func (alg * Algorand ) sortition (seed , role []byte , expectedNum int , weight uint64 ) (vrf , proof []byte , selected int ) {
267
- vrf , proof = alg .privkey .Evaluate (constructSeed (seed , role ))
274
+ vrf , proof , _ = alg .privkey .Evaluate (constructSeed (seed , role ))
268
275
selected = subUsers (expectedNum , weight , vrf )
269
276
return
270
277
}
271
278
272
279
// verifySort verifies the vrf and returns the amount of selected sub-users.
273
280
func (alg * Algorand ) verifySort (vrf , proof , seed , role []byte , expectedNum int ) int {
274
- if err := alg .publicKey () .VerifyVRF (vrf , proof , constructSeed (seed , role )); err != nil {
281
+ if err := alg .pubkey .VerifyVRF (proof , constructSeed (seed , role )); err != nil {
275
282
return 0
276
283
}
277
284
@@ -411,7 +418,7 @@ func (alg *Algorand) binaryBA(round uint64, hash common.Hash) common.Hash {
411
418
func (alg * Algorand ) countVotes (round uint64 , step int , threshold float64 , expectedNum int , timeout time.Duration ) (common.Hash , error ) {
412
419
expired := time .NewTimer (timeout )
413
420
counts := make (map [common.Hash ]int )
414
- voters := make (map [PublicKey ]struct {})
421
+ voters := make (map [string ]struct {})
415
422
it := alg .peer .voteIterator (round , step )
416
423
for {
417
424
msg := it .next ()
@@ -426,10 +433,10 @@ func (alg *Algorand) countVotes(round uint64, step int, threshold float64, expec
426
433
voteMsg := msg .(* VoteMessage )
427
434
votes , hash , _ := alg .processMsg (msg .(* VoteMessage ), expectedNum )
428
435
pubkey := voteMsg .RecoverPubkey ()
429
- if _ , exist := voters [* pubkey ]; exist || votes == 0 {
436
+ if _ , exist := voters [string ( pubkey . pk ) ]; exist || votes == 0 {
430
437
continue
431
438
}
432
- voters [* pubkey ] = struct {}{}
439
+ voters [string ( pubkey . pk ) ] = struct {}{}
433
440
counts [hash ] += votes
434
441
// if we got enough votes, then output the target hash
435
442
if uint64 (counts [hash ]) >= uint64 (float64 (expectedNum )* threshold ) {
0 commit comments