Skip to content

Commit 41dfb17

Browse files
committed
consensus/*, eth, ethstats, miner: add block lock and some features
* consensus/istanbul: handle future preprepare * consensus/istanbul: handle request timeout in evnet loop * consensus, eth: start/stop core engine while start/stop mining * eth, ethstats: fix crash while reporting to ethstats * consensus/istanbul, miner: add new event to trigger new block creation * eth, consensus/istanbul: improve sending messages * consensus/istanbul: stop future preprepare timer while stop core * consensus/istanbul: add cache in ecrecover()
1 parent 3730ecf commit 41dfb17

30 files changed

+718
-278
lines changed

consensus/consensus.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,15 @@ type PoW interface {
106106
type Istanbul interface {
107107
Engine
108108

109-
// Handle a message from peer
109+
// HandleMsg handles a message from peer
110110
HandleMsg(pubKey *ecdsa.PublicKey, data []byte) error
111111

112-
// Receive new chain head block
113-
NewChainHead(block *types.Block)
112+
// NewChainHead is called if a new chain head block comes
113+
NewChainHead(block *types.Block) error
114114

115-
// Start the engine
116-
Start(chain ChainReader, inserter func(block *types.Block) error) error
115+
// Start starts the engine
116+
Start(chain ChainReader, inserter func(types.Blocks) (int, error)) error
117117

118-
// Stop the engine
118+
// Stop stops the engine
119119
Stop() error
120120
}

consensus/istanbul/backend.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package istanbul
1818

1919
import (
20+
"math/big"
21+
"time"
22+
2023
"github.com/ethereum/go-ethereum/common"
2124
"github.com/ethereum/go-ethereum/event"
2225
)
@@ -32,26 +35,33 @@ type Backend interface {
3235
// EventMux returns the event mux in backend
3336
EventMux() *event.TypeMux
3437

35-
// Send sends a message to specific target
36-
Send(payload []byte, target common.Address) error
37-
3838
// Broadcast sends a message to all validators
3939
Broadcast(valSet ValidatorSet, payload []byte) error
4040

4141
// Commit delivers an approved proposal to backend.
4242
// The delivered proposal will be put into blockchain.
43-
Commit(proposal Proposal, seals []byte) error
43+
Commit(proposal Proposal, seals [][]byte) error
4444

4545
// NextRound is called when we want to trigger next Seal()
4646
NextRound() error
4747

48-
// Verify verifies the proposal.
49-
Verify(Proposal) error
48+
// Verify verifies the proposal. If a consensus.ErrFutureBlock error is returned,
49+
// the time difference of the proposal and current time is also returned.
50+
Verify(Proposal) (time.Duration, error)
5051

5152
// Sign signs input data with the backend's private key
5253
Sign([]byte) ([]byte, error)
5354

5455
// CheckSignature verifies the signature by checking if it's signed by
5556
// the given validator
5657
CheckSignature(data []byte, addr common.Address, sig []byte) error
58+
59+
// HasBlock checks if the combination of the given hash and height matches any existing blocks
60+
HasBlock(hash common.Hash, number *big.Int) bool
61+
62+
// GetProposer returns the proposer of the given block height
63+
GetProposer(number uint64) common.Address
64+
65+
// ParentValidators returns the validator set of the given proposal's parent block
66+
ParentValidators(proposal Proposal) ValidatorSet
5767
}

consensus/istanbul/backend/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
// API is a user facing RPC API to dump Istanbul state
2727
type API struct {
2828
chain consensus.ChainReader
29-
istanbul *simpleBackend
29+
istanbul *backend
3030
}
3131

3232
// GetSnapshot retrieves the state snapshot at a given block.

consensus/istanbul/backend/backend.go

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,61 +18,65 @@ package backend
1818

1919
import (
2020
"crypto/ecdsa"
21+
"math/big"
2122
"sync"
23+
"time"
2224

2325
"github.com/ethereum/go-ethereum/common"
2426
"github.com/ethereum/go-ethereum/consensus"
2527
"github.com/ethereum/go-ethereum/consensus/istanbul"
2628
istanbulCore "github.com/ethereum/go-ethereum/consensus/istanbul/core"
2729
"github.com/ethereum/go-ethereum/consensus/istanbul/validator"
28-
"github.com/ethereum/go-ethereum/core"
2930
"github.com/ethereum/go-ethereum/core/types"
3031
"github.com/ethereum/go-ethereum/crypto"
3132
"github.com/ethereum/go-ethereum/ethdb"
3233
"github.com/ethereum/go-ethereum/event"
3334
"github.com/ethereum/go-ethereum/log"
35+
"github.com/ethereum/go-ethereum/miner"
3436
lru "github.com/hashicorp/golang-lru"
3537
)
3638

3739
// New creates an Ethereum backend for Istanbul core engine.
3840
func New(config *istanbul.Config, eventMux *event.TypeMux, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.Istanbul {
3941
// Allocate the snapshot caches and create the engine
4042
recents, _ := lru.NewARC(inmemorySnapshots)
41-
backend := &simpleBackend{
43+
backend := &backend{
4244
config: config,
4345
eventMux: eventMux,
4446
istanbulEventMux: new(event.TypeMux),
4547
privateKey: privateKey,
4648
address: crypto.PubkeyToAddress(privateKey.PublicKey),
47-
logger: log.New("backend", "simple"),
49+
logger: log.New(),
4850
db: db,
4951
commitCh: make(chan *types.Block, 1),
5052
recents: recents,
5153
candidates: make(map[common.Address]bool),
54+
coreStarted: false,
5255
}
56+
backend.core = istanbulCore.New(backend, backend.config)
5357
return backend
5458
}
5559

5660
// ----------------------------------------------------------------------------
5761

58-
type simpleBackend struct {
62+
type backend struct {
5963
config *istanbul.Config
6064
eventMux *event.TypeMux
6165
istanbulEventMux *event.TypeMux
6266
privateKey *ecdsa.PrivateKey
6367
address common.Address
6468
core istanbulCore.Engine
6569
logger log.Logger
66-
quitSync chan struct{}
6770
db ethdb.Database
68-
timeout uint64
6971
chain consensus.ChainReader
70-
inserter func(block *types.Block) error
72+
inserter func(types.Blocks) (int, error)
7173

7274
// the channels for istanbul engine notifications
7375
commitCh chan *types.Block
7476
proposedBlockHash common.Hash
7577
sealMu sync.Mutex
78+
coreStarted bool
79+
coreMu sync.Mutex
7680

7781
// Current list of candidates we are pushing
7882
candidates map[common.Address]bool
@@ -83,29 +87,18 @@ type simpleBackend struct {
8387
}
8488

8589
// Address implements istanbul.Backend.Address
86-
func (sb *simpleBackend) Address() common.Address {
90+
func (sb *backend) Address() common.Address {
8791
return sb.address
8892
}
8993

9094
// Validators implements istanbul.Backend.Validators
91-
func (sb *simpleBackend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet {
92-
snap, err := sb.snapshot(sb.chain, proposal.Number().Uint64(), proposal.Hash(), nil)
93-
if err != nil {
94-
return validator.NewSet(nil, sb.config.ProposerPolicy)
95-
}
96-
return snap.ValSet
97-
}
98-
99-
func (sb *simpleBackend) Send(payload []byte, target common.Address) error {
100-
go sb.eventMux.Post(istanbul.ConsensusDataEvent{
101-
Target: target,
102-
Data: payload,
103-
})
104-
return nil
95+
func (sb *backend) Validators(proposal istanbul.Proposal) istanbul.ValidatorSet {
96+
return sb.getValidators(proposal.Number().Uint64(), proposal.Hash())
10597
}
10698

10799
// Broadcast implements istanbul.Backend.Send
108-
func (sb *simpleBackend) Broadcast(valSet istanbul.ValidatorSet, payload []byte) error {
100+
func (sb *backend) Broadcast(valSet istanbul.ValidatorSet, payload []byte) error {
101+
targets := make(map[common.Address]bool)
109102
for _, val := range valSet.List() {
110103
if val.Address() == sb.Address() {
111104
// send to self
@@ -116,14 +109,21 @@ func (sb *simpleBackend) Broadcast(valSet istanbul.ValidatorSet, payload []byte)
116109

117110
} else {
118111
// send to other peers
119-
sb.Send(payload, val.Address())
112+
targets[val.Address()] = true
120113
}
121114
}
115+
116+
if len(targets) > 0 {
117+
go sb.eventMux.Post(istanbul.ConsensusDataEvent{
118+
Targets: targets,
119+
Data: payload,
120+
})
121+
}
122122
return nil
123123
}
124124

125125
// Commit implements istanbul.Backend.Commit
126-
func (sb *simpleBackend) Commit(proposal istanbul.Proposal, seals []byte) error {
126+
func (sb *backend) Commit(proposal istanbul.Proposal, seals [][]byte) error {
127127
// Check if the proposal is a valid block
128128
block := &types.Block{}
129129
block, ok := proposal.(*types.Block)
@@ -154,49 +154,58 @@ func (sb *simpleBackend) Commit(proposal istanbul.Proposal, seals []byte) error
154154
// TODO: how do we check the block is inserted correctly?
155155
return nil
156156
}
157-
158-
return sb.inserter(block)
157+
// if I'm not a proposer, insert the block directly and broadcast NewCommittedEvent
158+
if _, err := sb.inserter(types.Blocks{block}); err != nil {
159+
return err
160+
}
161+
msg := istanbul.NewCommittedEvent{
162+
Block: block,
163+
}
164+
go sb.eventMux.Post(msg)
165+
return nil
159166
}
160167

161-
// NextRound will broadcast ChainHeadEvent to trigger next seal()
162-
func (sb *simpleBackend) NextRound() error {
168+
// NextRound will broadcast NewBlockEvent to trigger next seal()
169+
func (sb *backend) NextRound() error {
163170
header := sb.chain.CurrentHeader()
164171
sb.logger.Debug("NextRound", "address", sb.Address(), "current_hash", header.Hash(), "current_number", header.Number)
165-
go sb.eventMux.Post(core.ChainHeadEvent{})
172+
go sb.eventMux.Post(miner.NewBlockEvent{})
166173
return nil
167174
}
168175

169176
// EventMux implements istanbul.Backend.EventMux
170-
func (sb *simpleBackend) EventMux() *event.TypeMux {
177+
func (sb *backend) EventMux() *event.TypeMux {
171178
return sb.istanbulEventMux
172179
}
173180

174181
// Verify implements istanbul.Backend.Verify
175-
func (sb *simpleBackend) Verify(proposal istanbul.Proposal) error {
182+
func (sb *backend) Verify(proposal istanbul.Proposal) (time.Duration, error) {
176183
// Check if the proposal is a valid block
177184
block := &types.Block{}
178185
block, ok := proposal.(*types.Block)
179186
if !ok {
180187
sb.logger.Error("Invalid proposal, %v", proposal)
181-
return errInvalidProposal
188+
return 0, errInvalidProposal
182189
}
183190
// verify the header of proposed block
184191
err := sb.VerifyHeader(sb.chain, block.Header(), false)
185-
// Ignore errEmptyCommittedSeals error because we don't have the committed seals yet
186-
if err != nil && err != errEmptyCommittedSeals {
187-
return err
192+
// ignore errEmptyCommittedSeals error because we don't have the committed seals yet
193+
if err == nil || err == errEmptyCommittedSeals {
194+
return 0, nil
195+
} else if err == consensus.ErrFutureBlock {
196+
return time.Unix(block.Header().Time.Int64(), 0).Sub(now()), consensus.ErrFutureBlock
188197
}
189-
return nil
198+
return 0, err
190199
}
191200

192201
// Sign implements istanbul.Backend.Sign
193-
func (sb *simpleBackend) Sign(data []byte) ([]byte, error) {
202+
func (sb *backend) Sign(data []byte) ([]byte, error) {
194203
hashData := crypto.Keccak256([]byte(data))
195204
return crypto.Sign(hashData, sb.privateKey)
196205
}
197206

198207
// CheckSignature implements istanbul.Backend.CheckSignature
199-
func (sb *simpleBackend) CheckSignature(data []byte, address common.Address, sig []byte) error {
208+
func (sb *backend) CheckSignature(data []byte, address common.Address, sig []byte) error {
200209
signer, err := istanbul.GetSignatureAddress(data, sig)
201210
if err != nil {
202211
log.Error("Failed to get signer address", "err", err)
@@ -208,3 +217,33 @@ func (sb *simpleBackend) CheckSignature(data []byte, address common.Address, sig
208217
}
209218
return nil
210219
}
220+
221+
// HasBlock implements istanbul.Backend.HashBlock
222+
func (sb *backend) HasBlock(hash common.Hash, number *big.Int) bool {
223+
return sb.chain.GetHeader(hash, number.Uint64()) != nil
224+
}
225+
226+
// GetProposer implements istanbul.Backend.GetProposer
227+
func (sb *backend) GetProposer(number uint64) common.Address {
228+
if h := sb.chain.GetHeaderByNumber(number); h != nil {
229+
a, _ := sb.Author(h)
230+
return a
231+
}
232+
return common.Address{}
233+
}
234+
235+
// ParentValidators implements istanbul.Backend.GetParentValidators
236+
func (sb *backend) ParentValidators(proposal istanbul.Proposal) istanbul.ValidatorSet {
237+
if block, ok := proposal.(*types.Block); ok {
238+
return sb.getValidators(block.Number().Uint64()-1, block.ParentHash())
239+
}
240+
return validator.NewSet(nil, sb.config.ProposerPolicy)
241+
}
242+
243+
func (sb *backend) getValidators(number uint64, hash common.Hash) istanbul.ValidatorSet {
244+
snap, err := sb.snapshot(sb.chain, number, hash, nil)
245+
if err != nil {
246+
return validator.NewSet(nil, sb.config.ProposerPolicy)
247+
}
248+
return snap.ValSet
249+
}

0 commit comments

Comments
 (0)