/
pseudonode.go
143 lines (125 loc) · 4.04 KB
/
pseudonode.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
package algo
import (
"context"
"crypto/ecdsa"
"fmt"
"github.com/awesome-chain/Xchain/consensus"
"github.com/awesome-chain/Xchain/core/types"
"github.com/awesome-chain/Xchain/crypto"
"github.com/awesome-chain/Xchain/crypto/vrf"
"math/big"
"sync"
"time"
)
// AssemblyTime is the max amount of time to spend on generating a proposal block.
const AssemblyTime time.Duration = 250 * time.Millisecond
// TODO put these in config
const (
pseudonodeVerificationBacklog = 32
)
var errPseudonodeBacklogFull = fmt.Errorf("pseudonode input channel is full")
var errPseudonodeVerifierClosedChannel = fmt.Errorf("crypto verifier closed the output channel prematurely")
var errPseudonodeNoVotes = fmt.Errorf("no valid participation keys to generate votes for given round")
var errPseudonodeNoProposals = fmt.Errorf("no valid participation keys to generate proposals for given round")
type AsyncPseudoNode struct {
factory BlockFactory
validator BlockValidator
ledger consensus.ChainReader
quit chan struct{}
closeWG *sync.WaitGroup
proposalsVerifier *PseudoNodeVerifier
}
// PseudoNodeTask encapsulates a single task which should be executed by the pseudonode.
type PseudoNodeTask interface {
// Execute a task with a given cryptoVerifier and quit channel.
execute(verifier *AsyncVoteVerifier, quit chan struct{})
}
type PseudoNodeBaseTask struct {
node *AsyncPseudoNode
context context.Context // the context associated with that task; context might expire for a single task but remain valid for others.
out chan externalEvent
}
type PseudoNodeProposalsTask struct {
PseudoNodeBaseTask
round uint64
period uint64
}
type PseudoNodeVerifier struct {
verifier *AsyncVoteVerifier
incomingTasks chan PseudoNodeTask
}
func (n *AsyncPseudoNode) MakeProposals(ctx context.Context, r uint64, p uint64) (<-chan externalEvent, error) {
proposalTask := n.makeProposalsTask(ctx, r, p)
select {
case n.proposalsVerifier.incomingTasks <- proposalTask:
return proposalTask.outputChannel(), nil
default:
proposalTask.close()
return nil, errPseudonodeBacklogFull
}
}
// makeProposals creates a slice of block proposals for the given round and period.
func (n *AsyncPseudoNode) makeProposals(round uint64, period uint64, sk *ecdsa.PrivateKey) []*Proposal {
//deadline := time.Now().Add(AssemblyTime)
proposals := make([]*Proposal, 0)
address := crypto.PubkeyToAddress(sk.PublicKey)
newSeed, seedProof, err := DeriveNewSeed(address, &vrf.PrivateKey{sk}, round, period, n.ledger)
if err != nil {
return nil
}
header := &types.Header{
Coinbase: address,
Number: new(big.Int).SetUint64(round),
}
header.Seed = newSeed
b := types.NewBlock(header, nil, nil, nil)
p := MakeProposal(b, seedProof[:], 0, &sk.PublicKey)
// create the block proposal
proposals = append(proposals, p)
return proposals
}
func (n *AsyncPseudoNode) makeProposalsTask(ctx context.Context, r uint64, p uint64) *PseudoNodeProposalsTask {
pt := &PseudoNodeProposalsTask{
PseudoNodeBaseTask: PseudoNodeBaseTask{
node: n,
context: ctx,
out: make(chan externalEvent),
},
round: r,
period: p,
}
return pt
}
func (t *PseudoNodeProposalsTask) execute(verifier *AsyncVoteVerifier, quit chan struct{}) {
defer t.close()
// check to see if task already expired.
//if t.context.Err() != nil {
// return
//}
//payloads, votes := t.node.makeProposals(t.round, t.period, t.participation)
return
}
func (t *PseudoNodeBaseTask) outputChannel() chan externalEvent {
return t.out
}
func (t *PseudoNodeBaseTask) close() {
close(t.out)
}
//func (n *AsyncPseudoNode) Quit() {
// // protect against double-quits.
// select {
// case <-n.quit:
// // if we already quit, just exit.
// return
// default:
// }
// close(n.quit)
// n.proposalsVerifier.close()
// n.votesVerifier.close()
// n.closeWg.Wait()
//}
// PseudoNodeTask encapsulates a single task which should be executed by the pseudonode.
//type PseudoNodeTask interface {
// // Execute a task with a given cryptoVerifier and quit channel.
// execute(verifier *AsyncVoteVerifier, quit chan struct{})
//}