2019-11-08 15:40:21 +00:00
|
|
|
package consensus
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
import (
|
|
|
|
"errors"
|
2020-11-17 12:57:50 +00:00
|
|
|
"fmt"
|
2019-11-15 10:32:40 +00:00
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/dbft"
|
|
|
|
"github.com/nspcc-dev/dbft/block"
|
|
|
|
"github.com/nspcc-dev/dbft/crypto"
|
|
|
|
"github.com/nspcc-dev/dbft/payload"
|
2020-06-26 14:23:10 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
2020-06-18 09:00:51 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-03-03 14:21:42 +00:00
|
|
|
coreb "github.com/nspcc-dev/neo-go/pkg/core/block"
|
2020-04-08 10:56:04 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
2020-08-19 16:27:15 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
2020-11-09 12:11:51 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2020-06-25 08:16:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-08-19 13:55:01 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
2020-04-21 13:45:48 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-04-21 13:45:48 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
"go.uber.org/atomic"
|
2019-11-15 10:32:40 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
2019-11-08 15:40:21 +00:00
|
|
|
|
|
|
|
// cacheMaxCapacity is the default cache capacity taken
|
|
|
|
// from C# implementation https://github.com/neo-project/neo/blob/master/neo/Ledger/Blockchain.cs#L64
|
|
|
|
const cacheMaxCapacity = 100
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
// defaultTimePerBlock is a period between blocks which is used in NEO.
|
|
|
|
const defaultTimePerBlock = 15 * time.Second
|
|
|
|
|
2020-07-11 12:22:14 +00:00
|
|
|
// Number of nanoseconds in millisecond.
|
|
|
|
const nsInMs = 1000000
|
|
|
|
|
2019-11-08 15:40:21 +00:00
|
|
|
// Service represents consensus instance.
|
|
|
|
type Service interface {
|
2019-11-15 10:32:40 +00:00
|
|
|
// Start initializes dBFT and starts event loop for consensus service.
|
|
|
|
// It must be called only when sufficient amount of peers are connected.
|
|
|
|
Start()
|
2020-09-01 16:58:51 +00:00
|
|
|
// Shutdown stops dBFT event loop.
|
|
|
|
Shutdown()
|
2019-11-15 10:32:40 +00:00
|
|
|
|
|
|
|
// OnPayload is a callback to notify Service about new received payload.
|
2019-11-08 15:40:21 +00:00
|
|
|
OnPayload(p *Payload)
|
2019-11-15 10:32:40 +00:00
|
|
|
// OnTransaction is a callback to notify Service about new received transaction.
|
|
|
|
OnTransaction(tx *transaction.Transaction)
|
|
|
|
// GetPayload returns Payload with specified hash if it is present in the local cache.
|
2019-11-08 15:40:21 +00:00
|
|
|
GetPayload(h util.Uint256) *Payload
|
|
|
|
}
|
|
|
|
|
|
|
|
type service struct {
|
2019-11-15 10:32:40 +00:00
|
|
|
Config
|
|
|
|
|
2020-01-09 14:46:08 +00:00
|
|
|
log *zap.Logger
|
2019-11-15 10:32:40 +00:00
|
|
|
// cache is a fifo cache which stores recent payloads.
|
2019-11-08 15:40:21 +00:00
|
|
|
cache *relayCache
|
2019-11-15 10:32:40 +00:00
|
|
|
// txx is a fifo cache which stores miner transactions.
|
|
|
|
txx *relayCache
|
|
|
|
dbft *dbft.DBFT
|
|
|
|
// messages and transactions are channels needed to process
|
|
|
|
// everything in single thread.
|
|
|
|
messages chan Payload
|
|
|
|
transactions chan *transaction.Transaction
|
2020-02-17 13:20:04 +00:00
|
|
|
// blockEvents is used to pass a new block event to the consensus
|
|
|
|
// process.
|
2020-05-07 19:45:06 +00:00
|
|
|
blockEvents chan *coreb.Block
|
2020-01-14 11:34:09 +00:00
|
|
|
lastProposal []util.Uint256
|
2020-01-15 14:05:47 +00:00
|
|
|
wallet *wallet.Wallet
|
2020-06-18 09:00:51 +00:00
|
|
|
network netmode.Magic
|
2020-11-17 12:57:50 +00:00
|
|
|
// stateRootEnabled specifies if state root should be exchanged and checked during consensus.
|
|
|
|
stateRootEnabled bool
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
// started is a flag set with Start method that runs an event handling
|
|
|
|
// goroutine.
|
consensus: wait goroutine to finish on Shutdown
Fixes:
panic: assignment to entry in nil map
goroutine 227 [running]:
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).put(...)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:53
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).PutBatch(0xc00035f580, 0x110a680, 0xc000336750, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:93 +0x286
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000a2340, 0xc0001be301, 0xc00036d428, 0x1, 0x1, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:516 +0xd5a
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock(0xc0000a2340, 0xc0000bc2c0, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:407 +0x9ca
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).processBlock(0xc000152160, 0x1122320, 0xc0000bc2c0)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:440 +0xbf
github.com/nspcc-dev/dbft.(*DBFT).checkCommit(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:71 +0x918
github.com/nspcc-dev/dbft.(*DBFT).checkPrepare(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:36 +0x465
github.com/nspcc-dev/dbft.(*DBFT).sendPrepareRequest(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/send.go:42 +0x2f8
github.com/nspcc-dev/dbft.(*DBFT).start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:269 +0x26f
github.com/nspcc-dev/dbft.(*DBFT).Start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:82 +0x59
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).Start(0xc000152160)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:191 +0x56
github.com/nspcc-dev/neo-go/pkg/network.(*Server).tryStartConsensus(0xc000235040)
/home/rik/dev/neo-go/pkg/network/server.go:311 +0xda
github.com/nspcc-dev/neo-go/pkg/network.(*Server).Start(0xc000235040, 0xc0000faba0)
/home/rik/dev/neo-go/pkg/network/server.go:173 +0x202
created by github.com/nspcc-dev/neo-go/cli.newTestChain
/home/rik/dev/neo-go/cli/executor_test.go:77 +0x47d
FAIL github.com/nspcc-dev/neo-go/cli 14.479s
2020-09-19 18:49:05 +00:00
|
|
|
started *atomic.Bool
|
|
|
|
quit chan struct{}
|
|
|
|
finished chan struct{}
|
2020-12-16 10:24:49 +00:00
|
|
|
// lastTimestamp contains timestamp for the last processed block.
|
|
|
|
// We can't rely on timestamp from dbft context because it is changed
|
|
|
|
// before block is accepted, so in case of change view it will contain
|
|
|
|
// updated value.
|
|
|
|
lastTimestamp uint64
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Config is a configuration for consensus services.
|
|
|
|
type Config struct {
|
2019-12-30 07:43:05 +00:00
|
|
|
// Logger is a logger instance.
|
|
|
|
Logger *zap.Logger
|
2019-11-15 10:32:40 +00:00
|
|
|
// Broadcast is a callback which is called to notify server
|
|
|
|
// about new consensus payload to sent.
|
|
|
|
Broadcast func(p *Payload)
|
|
|
|
// Chain is a core.Blockchainer instance.
|
2020-04-08 10:56:04 +00:00
|
|
|
Chain blockchainer.Blockchainer
|
2019-11-15 10:32:40 +00:00
|
|
|
// RequestTx is a callback to which will be called
|
|
|
|
// when a node lacks transactions present in a block.
|
|
|
|
RequestTx func(h ...util.Uint256)
|
|
|
|
// TimePerBlock minimal time that should pass before next block is accepted.
|
|
|
|
TimePerBlock time.Duration
|
|
|
|
// Wallet is a local-node wallet configuration.
|
2020-06-26 14:23:10 +00:00
|
|
|
Wallet *config.Wallet
|
2019-11-08 15:40:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewService returns new consensus.Service instance.
|
2019-11-15 10:32:40 +00:00
|
|
|
func NewService(cfg Config) (Service, error) {
|
|
|
|
if cfg.TimePerBlock <= 0 {
|
|
|
|
cfg.TimePerBlock = defaultTimePerBlock
|
|
|
|
}
|
|
|
|
|
2019-12-30 07:43:05 +00:00
|
|
|
if cfg.Logger == nil {
|
|
|
|
return nil, errors.New("empty logger")
|
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
srv := &service{
|
|
|
|
Config: cfg,
|
|
|
|
|
2020-01-09 14:46:08 +00:00
|
|
|
log: cfg.Logger,
|
2019-11-15 10:32:40 +00:00
|
|
|
cache: newFIFOCache(cacheMaxCapacity),
|
|
|
|
txx: newFIFOCache(cacheMaxCapacity),
|
|
|
|
messages: make(chan Payload, 100),
|
2019-11-29 12:40:11 +00:00
|
|
|
|
2020-11-17 12:57:50 +00:00
|
|
|
transactions: make(chan *transaction.Transaction, 100),
|
|
|
|
blockEvents: make(chan *coreb.Block, 1),
|
|
|
|
network: cfg.Chain.GetConfig().Magic,
|
|
|
|
stateRootEnabled: cfg.Chain.GetConfig().StateRootInHeader,
|
|
|
|
started: atomic.NewBool(false),
|
|
|
|
quit: make(chan struct{}),
|
|
|
|
finished: make(chan struct{}),
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if cfg.Wallet == nil {
|
|
|
|
return srv, nil
|
|
|
|
}
|
|
|
|
|
2020-01-15 14:05:47 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
if srv.wallet, err = wallet.NewWalletFromFile(cfg.Wallet.Path); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-13 09:01:18 +00:00
|
|
|
// Check that wallet password is correct for at least one account.
|
|
|
|
var ok bool
|
|
|
|
for _, acc := range srv.wallet.Accounts {
|
|
|
|
err := acc.Decrypt(srv.Config.Wallet.Password)
|
|
|
|
if err == nil {
|
|
|
|
ok = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("no account with provided password was found")
|
|
|
|
}
|
|
|
|
|
2020-01-15 14:05:47 +00:00
|
|
|
defer srv.wallet.Close()
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
srv.dbft = dbft.New(
|
2020-01-09 14:46:08 +00:00
|
|
|
dbft.WithLogger(srv.log),
|
2019-11-15 10:32:40 +00:00
|
|
|
dbft.WithSecondsPerBlock(cfg.TimePerBlock),
|
2020-01-17 14:30:45 +00:00
|
|
|
dbft.WithGetKeyPair(srv.getKeyPair),
|
2019-11-15 10:32:40 +00:00
|
|
|
dbft.WithRequestTx(cfg.RequestTx),
|
|
|
|
dbft.WithGetTx(srv.getTx),
|
|
|
|
dbft.WithGetVerified(srv.getVerifiedTx),
|
|
|
|
dbft.WithBroadcast(srv.broadcast),
|
|
|
|
dbft.WithProcessBlock(srv.processBlock),
|
|
|
|
dbft.WithVerifyBlock(srv.verifyBlock),
|
|
|
|
dbft.WithGetBlock(srv.getBlock),
|
|
|
|
dbft.WithWatchOnly(func() bool { return false }),
|
2020-06-18 09:00:51 +00:00
|
|
|
dbft.WithNewBlockFromContext(srv.newBlockFromContext),
|
2019-11-15 10:32:40 +00:00
|
|
|
dbft.WithCurrentHeight(cfg.Chain.BlockHeight),
|
|
|
|
dbft.WithCurrentBlockHash(cfg.Chain.CurrentBlockHash),
|
|
|
|
dbft.WithGetValidators(srv.getValidators),
|
|
|
|
dbft.WithGetConsensusAddress(srv.getConsensusAddress),
|
|
|
|
|
2020-06-26 15:27:18 +00:00
|
|
|
dbft.WithNewConsensusPayload(srv.newPayload),
|
2020-11-17 12:57:50 +00:00
|
|
|
dbft.WithNewPrepareRequest(srv.newPrepareRequest),
|
2019-11-15 10:32:40 +00:00
|
|
|
dbft.WithNewPrepareResponse(func() payload.PrepareResponse { return new(prepareResponse) }),
|
|
|
|
dbft.WithNewChangeView(func() payload.ChangeView { return new(changeView) }),
|
|
|
|
dbft.WithNewCommit(func() payload.Commit { return new(commit) }),
|
2020-01-29 14:56:21 +00:00
|
|
|
dbft.WithNewRecoveryRequest(func() payload.RecoveryRequest { return new(recoveryRequest) }),
|
2020-11-17 12:57:50 +00:00
|
|
|
dbft.WithNewRecoveryMessage(func() payload.RecoveryMessage {
|
|
|
|
return &recoveryMessage{stateRootEnabled: srv.stateRootEnabled}
|
|
|
|
}),
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
dbft.WithVerifyPrepareRequest(srv.verifyRequest),
|
2020-09-03 19:02:42 +00:00
|
|
|
dbft.WithVerifyPrepareResponse(func(_ payload.ConsensusPayload) error { return nil }),
|
2019-11-15 10:32:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if srv.dbft == nil {
|
|
|
|
return nil, errors.New("can't initialize dBFT")
|
|
|
|
}
|
|
|
|
|
|
|
|
return srv, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
_ block.Transaction = (*transaction.Transaction)(nil)
|
|
|
|
_ block.Block = (*neoBlock)(nil)
|
|
|
|
)
|
|
|
|
|
2020-08-18 14:41:22 +00:00
|
|
|
// NewPayload creates new consensus payload for the provided network.
|
2020-11-17 12:57:50 +00:00
|
|
|
func NewPayload(m netmode.Magic, stateRootEnabled bool) *Payload {
|
2020-06-26 15:27:18 +00:00
|
|
|
return &Payload{
|
|
|
|
network: m,
|
2020-11-17 12:57:50 +00:00
|
|
|
message: &message{
|
|
|
|
stateRootEnabled: stateRootEnabled,
|
|
|
|
},
|
2020-06-26 15:27:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) newPayload() payload.ConsensusPayload {
|
2020-11-17 12:57:50 +00:00
|
|
|
return NewPayload(s.network, s.stateRootEnabled)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) newPrepareRequest() payload.PrepareRequest {
|
|
|
|
r := new(prepareRequest)
|
|
|
|
if s.stateRootEnabled {
|
|
|
|
r.stateRootEnabled = true
|
|
|
|
if sr, err := s.Chain.GetStateRoot(s.dbft.BlockIndex - 1); err == nil {
|
|
|
|
r.stateRoot = sr.Root
|
|
|
|
} else {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r
|
2020-06-26 15:27:18 +00:00
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
func (s *service) Start() {
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
if s.started.CAS(false, true) {
|
|
|
|
s.dbft.Start()
|
|
|
|
s.Chain.SubscribeForBlocks(s.blockEvents)
|
|
|
|
go s.eventLoop()
|
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 16:58:51 +00:00
|
|
|
// Shutdown implements Service interface.
|
|
|
|
func (s *service) Shutdown() {
|
|
|
|
close(s.quit)
|
consensus: wait goroutine to finish on Shutdown
Fixes:
panic: assignment to entry in nil map
goroutine 227 [running]:
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).put(...)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:53
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).PutBatch(0xc00035f580, 0x110a680, 0xc000336750, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:93 +0x286
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000a2340, 0xc0001be301, 0xc00036d428, 0x1, 0x1, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:516 +0xd5a
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock(0xc0000a2340, 0xc0000bc2c0, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:407 +0x9ca
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).processBlock(0xc000152160, 0x1122320, 0xc0000bc2c0)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:440 +0xbf
github.com/nspcc-dev/dbft.(*DBFT).checkCommit(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:71 +0x918
github.com/nspcc-dev/dbft.(*DBFT).checkPrepare(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:36 +0x465
github.com/nspcc-dev/dbft.(*DBFT).sendPrepareRequest(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/send.go:42 +0x2f8
github.com/nspcc-dev/dbft.(*DBFT).start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:269 +0x26f
github.com/nspcc-dev/dbft.(*DBFT).Start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:82 +0x59
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).Start(0xc000152160)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:191 +0x56
github.com/nspcc-dev/neo-go/pkg/network.(*Server).tryStartConsensus(0xc000235040)
/home/rik/dev/neo-go/pkg/network/server.go:311 +0xda
github.com/nspcc-dev/neo-go/pkg/network.(*Server).Start(0xc000235040, 0xc0000faba0)
/home/rik/dev/neo-go/pkg/network/server.go:173 +0x202
created by github.com/nspcc-dev/neo-go/cli.newTestChain
/home/rik/dev/neo-go/cli/executor_test.go:77 +0x47d
FAIL github.com/nspcc-dev/neo-go/cli 14.479s
2020-09-19 18:49:05 +00:00
|
|
|
<-s.finished
|
2020-09-01 16:58:51 +00:00
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
func (s *service) eventLoop() {
|
consensus: wait goroutine to finish on Shutdown
Fixes:
panic: assignment to entry in nil map
goroutine 227 [running]:
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).put(...)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:53
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).PutBatch(0xc00035f580, 0x110a680, 0xc000336750, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:93 +0x286
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000a2340, 0xc0001be301, 0xc00036d428, 0x1, 0x1, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:516 +0xd5a
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock(0xc0000a2340, 0xc0000bc2c0, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:407 +0x9ca
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).processBlock(0xc000152160, 0x1122320, 0xc0000bc2c0)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:440 +0xbf
github.com/nspcc-dev/dbft.(*DBFT).checkCommit(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:71 +0x918
github.com/nspcc-dev/dbft.(*DBFT).checkPrepare(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:36 +0x465
github.com/nspcc-dev/dbft.(*DBFT).sendPrepareRequest(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/send.go:42 +0x2f8
github.com/nspcc-dev/dbft.(*DBFT).start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:269 +0x26f
github.com/nspcc-dev/dbft.(*DBFT).Start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:82 +0x59
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).Start(0xc000152160)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:191 +0x56
github.com/nspcc-dev/neo-go/pkg/network.(*Server).tryStartConsensus(0xc000235040)
/home/rik/dev/neo-go/pkg/network/server.go:311 +0xda
github.com/nspcc-dev/neo-go/pkg/network.(*Server).Start(0xc000235040, 0xc0000faba0)
/home/rik/dev/neo-go/pkg/network/server.go:173 +0x202
created by github.com/nspcc-dev/neo-go/cli.newTestChain
/home/rik/dev/neo-go/cli/executor_test.go:77 +0x47d
FAIL github.com/nspcc-dev/neo-go/cli 14.479s
2020-09-19 18:49:05 +00:00
|
|
|
events:
|
2019-11-15 10:32:40 +00:00
|
|
|
for {
|
|
|
|
select {
|
2020-09-01 16:58:51 +00:00
|
|
|
case <-s.quit:
|
|
|
|
s.dbft.Timer.Stop()
|
consensus: wait goroutine to finish on Shutdown
Fixes:
panic: assignment to entry in nil map
goroutine 227 [running]:
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).put(...)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:53
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).PutBatch(0xc00035f580, 0x110a680, 0xc000336750, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:93 +0x286
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000a2340, 0xc0001be301, 0xc00036d428, 0x1, 0x1, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:516 +0xd5a
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock(0xc0000a2340, 0xc0000bc2c0, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:407 +0x9ca
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).processBlock(0xc000152160, 0x1122320, 0xc0000bc2c0)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:440 +0xbf
github.com/nspcc-dev/dbft.(*DBFT).checkCommit(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:71 +0x918
github.com/nspcc-dev/dbft.(*DBFT).checkPrepare(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:36 +0x465
github.com/nspcc-dev/dbft.(*DBFT).sendPrepareRequest(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/send.go:42 +0x2f8
github.com/nspcc-dev/dbft.(*DBFT).start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:269 +0x26f
github.com/nspcc-dev/dbft.(*DBFT).Start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:82 +0x59
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).Start(0xc000152160)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:191 +0x56
github.com/nspcc-dev/neo-go/pkg/network.(*Server).tryStartConsensus(0xc000235040)
/home/rik/dev/neo-go/pkg/network/server.go:311 +0xda
github.com/nspcc-dev/neo-go/pkg/network.(*Server).Start(0xc000235040, 0xc0000faba0)
/home/rik/dev/neo-go/pkg/network/server.go:173 +0x202
created by github.com/nspcc-dev/neo-go/cli.newTestChain
/home/rik/dev/neo-go/cli/executor_test.go:77 +0x47d
FAIL github.com/nspcc-dev/neo-go/cli 14.479s
2020-09-19 18:49:05 +00:00
|
|
|
break events
|
2020-09-10 13:34:33 +00:00
|
|
|
case <-s.dbft.Timer.C():
|
|
|
|
hv := s.dbft.Timer.HV()
|
2020-01-09 14:46:08 +00:00
|
|
|
s.log.Debug("timer fired",
|
|
|
|
zap.Uint32("height", hv.Height),
|
|
|
|
zap.Uint("view", uint(hv.View)))
|
2020-02-17 13:20:04 +00:00
|
|
|
s.dbft.OnTimeout(hv)
|
2019-11-15 10:32:40 +00:00
|
|
|
case msg := <-s.messages:
|
2020-01-31 11:31:19 +00:00
|
|
|
fields := []zap.Field{
|
2020-08-23 13:44:56 +00:00
|
|
|
zap.Uint8("from", msg.validatorIndex),
|
2020-01-31 11:31:19 +00:00
|
|
|
zap.Stringer("type", msg.Type()),
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type() == payload.RecoveryMessageType {
|
|
|
|
rec := msg.GetRecoveryMessage().(*recoveryMessage)
|
2020-01-31 12:02:03 +00:00
|
|
|
if rec.preparationHash == nil {
|
|
|
|
req := rec.GetPrepareRequest(&msg, s.dbft.Validators, uint16(s.dbft.PrimaryIndex))
|
|
|
|
if req != nil {
|
|
|
|
h := req.Hash()
|
|
|
|
rec.preparationHash = &h
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-31 11:31:19 +00:00
|
|
|
fields = append(fields,
|
|
|
|
zap.Int("#preparation", len(rec.preparationPayloads)),
|
|
|
|
zap.Int("#commit", len(rec.commitPayloads)),
|
|
|
|
zap.Int("#changeview", len(rec.changeViewPayloads)),
|
2020-01-31 11:49:15 +00:00
|
|
|
zap.Bool("#request", rec.prepareRequest != nil),
|
|
|
|
zap.Bool("#hash", rec.preparationHash != nil))
|
2020-01-31 11:31:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.log.Debug("received message", fields...)
|
2019-11-15 10:32:40 +00:00
|
|
|
s.dbft.OnReceive(&msg)
|
|
|
|
case tx := <-s.transactions:
|
|
|
|
s.dbft.OnTransaction(tx)
|
2020-05-07 19:45:06 +00:00
|
|
|
case b := <-s.blockEvents:
|
2020-09-17 15:27:27 +00:00
|
|
|
s.handleChainBlock(b)
|
|
|
|
}
|
|
|
|
// Always process block event if there is any, we can add one above.
|
|
|
|
select {
|
|
|
|
case b := <-s.blockEvents:
|
|
|
|
s.handleChainBlock(b)
|
|
|
|
default:
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
2020-09-17 15:27:27 +00:00
|
|
|
|
|
|
|
}
|
consensus: wait goroutine to finish on Shutdown
Fixes:
panic: assignment to entry in nil map
goroutine 227 [running]:
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).put(...)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:53
github.com/nspcc-dev/neo-go/pkg/core/storage.(*MemoryStore).PutBatch(0xc00035f580, 0x110a680, 0xc000336750, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/storage/memory_store.go:93 +0x286
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).addHeaders(0xc0000a2340, 0xc0001be301, 0xc00036d428, 0x1, 0x1, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:516 +0xd5a
github.com/nspcc-dev/neo-go/pkg/core.(*Blockchain).AddBlock(0xc0000a2340, 0xc0000bc2c0, 0x0, 0x0)
/home/rik/dev/neo-go/pkg/core/blockchain.go:407 +0x9ca
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).processBlock(0xc000152160, 0x1122320, 0xc0000bc2c0)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:440 +0xbf
github.com/nspcc-dev/dbft.(*DBFT).checkCommit(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:71 +0x918
github.com/nspcc-dev/dbft.(*DBFT).checkPrepare(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/check.go:36 +0x465
github.com/nspcc-dev/dbft.(*DBFT).sendPrepareRequest(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/send.go:42 +0x2f8
github.com/nspcc-dev/dbft.(*DBFT).start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:269 +0x26f
github.com/nspcc-dev/dbft.(*DBFT).Start(0xc0000d3400)
/home/rik/go/pkg/mod/github.com/nspcc-dev/dbft@v0.0.0-20200911152629-be965ee4d449/dbft.go:82 +0x59
github.com/nspcc-dev/neo-go/pkg/consensus.(*service).Start(0xc000152160)
/home/rik/dev/neo-go/pkg/consensus/consensus.go:191 +0x56
github.com/nspcc-dev/neo-go/pkg/network.(*Server).tryStartConsensus(0xc000235040)
/home/rik/dev/neo-go/pkg/network/server.go:311 +0xda
github.com/nspcc-dev/neo-go/pkg/network.(*Server).Start(0xc000235040, 0xc0000faba0)
/home/rik/dev/neo-go/pkg/network/server.go:173 +0x202
created by github.com/nspcc-dev/neo-go/cli.newTestChain
/home/rik/dev/neo-go/cli/executor_test.go:77 +0x47d
FAIL github.com/nspcc-dev/neo-go/cli 14.479s
2020-09-19 18:49:05 +00:00
|
|
|
close(s.finished)
|
2020-09-17 15:27:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) handleChainBlock(b *coreb.Block) {
|
|
|
|
// We can get our own block here, so check for index.
|
|
|
|
if b.Index >= s.dbft.BlockIndex {
|
|
|
|
s.log.Debug("new block in the chain",
|
|
|
|
zap.Uint32("dbft index", s.dbft.BlockIndex),
|
|
|
|
zap.Uint32("chain index", s.Chain.BlockHeight()))
|
2020-12-16 10:24:49 +00:00
|
|
|
if s.lastTimestamp < b.Timestamp {
|
|
|
|
s.lastTimestamp = b.Timestamp
|
|
|
|
}
|
2020-09-17 15:27:27 +00:00
|
|
|
s.dbft.InitializeConsensus(0)
|
2019-11-08 15:40:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 08:57:49 +00:00
|
|
|
func (s *service) validatePayload(p *Payload) bool {
|
|
|
|
validators := s.getValidators()
|
|
|
|
if int(p.validatorIndex) >= len(validators) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
pub := validators[p.validatorIndex]
|
2020-02-19 09:10:36 +00:00
|
|
|
h := pub.(*publicKey).GetScriptHash()
|
2019-12-16 08:57:49 +00:00
|
|
|
|
2020-08-20 08:02:11 +00:00
|
|
|
return s.Chain.VerifyWitness(h, p, &p.Witness, payloadGasLimit) == nil
|
2019-12-16 08:57:49 +00:00
|
|
|
}
|
|
|
|
|
2020-01-15 14:05:47 +00:00
|
|
|
func (s *service) getKeyPair(pubs []crypto.PublicKey) (int, crypto.PrivateKey, crypto.PublicKey) {
|
|
|
|
for i := range pubs {
|
2020-02-19 09:10:36 +00:00
|
|
|
sh := pubs[i].(*publicKey).GetScriptHash()
|
|
|
|
acc := s.wallet.GetAccount(sh)
|
2020-01-15 14:05:47 +00:00
|
|
|
if acc == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-08-19 13:55:01 +00:00
|
|
|
key := acc.PrivateKey()
|
|
|
|
if acc.PrivateKey() == nil {
|
|
|
|
err := acc.Decrypt(s.Config.Wallet.Password)
|
|
|
|
if err != nil {
|
|
|
|
s.log.Fatal("can't unlock account", zap.String("address", address.Uint160ToString(sh)))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
key = acc.PrivateKey()
|
2020-01-15 14:05:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return i, &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
2020-01-15 14:05:47 +00:00
|
|
|
return -1, nil, nil
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
2019-11-08 15:40:21 +00:00
|
|
|
// OnPayload handles Payload receive.
|
2019-11-15 10:32:40 +00:00
|
|
|
func (s *service) OnPayload(cp *Payload) {
|
2020-04-15 15:56:45 +00:00
|
|
|
log := s.log.With(zap.Stringer("hash", cp.Hash()))
|
2020-06-29 07:21:44 +00:00
|
|
|
if s.cache.Has(cp.Hash()) {
|
2020-01-31 11:31:19 +00:00
|
|
|
log.Debug("payload is already in cache")
|
2019-11-15 10:32:40 +00:00
|
|
|
return
|
2020-06-29 07:21:44 +00:00
|
|
|
} else if !s.validatePayload(cp) {
|
|
|
|
log.Debug("can't validate payload")
|
|
|
|
return
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
s.Config.Broadcast(cp)
|
|
|
|
s.cache.Add(cp)
|
|
|
|
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
if s.dbft == nil || !s.started.Load() {
|
|
|
|
log.Debug("dbft is inactive or not started yet")
|
2019-11-15 10:32:40 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-04-15 15:56:45 +00:00
|
|
|
// decode payload data into message
|
consensus: prevent `invalid message` panic
After 5c2f69bd2cff98382b4b458462d488e1945f3f37 there's an `invalid
message` panic when trying to run 4-nodes private network:
```
=> Try to restore blocks before running node
2020-06-30T08:59:39.696Z INFO no storage version found! creating genesis block
2020-06-30T08:59:39.696Z INFO service is running {"service": "Prometheus", "endpoint": ":20001"}
2020-06-30T08:59:39.696Z INFO service hasn't started since it's disabled {"service": "Pprof"}
_ ____________ __________
/ | / / ____/ __ \ / ____/ __ \
/ |/ / __/ / / / /_____/ / __/ / / /
/ /| / /___/ /_/ /_____/ /_/ / /_/ /
/_/ |_/_____/\____/ \____/\____/
2020-06-30T08:59:39.696Z INFO starting rpc-server {"endpoint": ":30333"}
2020-06-30T08:59:39.696Z INFO node started {"blockHeight": 0, "headerHeight": 0}
/NEO-GO:/
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.1:20333", "peerCount": 1}
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.2:46692", "peerCount": 2}
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.1:54140", "peerCount": 3}
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.4:42890", "peerCount": 4}
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.4:20336", "peerCount": 5}
2020-06-30T08:59:39.697Z INFO new peer connected {"addr": "172.200.0.2:20334", "peerCount": 6}
2020-06-30T08:59:39.697Z INFO started protocol {"addr": "172.200.0.4:42890", "userAgent": "/NEO-GO:/", "startHeight": 0, "id": 3797159912}
2020-06-30T08:59:39.697Z WARN peer disconnected {"addr": "172.200.0.4:20336", "reason": "already connected", "peerCount": 5}
2020-06-30T08:59:39.697Z INFO started protocol {"addr": "172.200.0.2:20334", "userAgent": "/NEO-GO:/", "startHeight": 0, "id": 1116452361}
2020-06-30T08:59:39.697Z WARN peer disconnected {"addr": "172.200.0.2:46692", "reason": "already connected", "peerCount": 4}
2020-06-30T08:59:39.697Z WARN peer disconnected {"addr": "172.200.0.1:54140", "reason": "identical node id", "peerCount": 3}
2020-06-30T08:59:39.697Z WARN peer disconnected {"addr": "172.200.0.1:20333", "reason": "identical node id", "peerCount": 2}
2020-06-30T08:59:40.673Z INFO new peer connected {"addr": "172.200.0.3:44948", "peerCount": 3}
2020-06-30T08:59:40.673Z INFO new peer connected {"addr": "172.200.0.3:20335", "peerCount": 4}
2020-06-30T08:59:40.673Z WARN peer disconnected {"addr": "172.200.0.3:20335", "reason": "already connected", "peerCount": 3}
2020-06-30T08:59:40.673Z WARN peer disconnected {"addr": "172.200.0.3:44948", "reason": "unexpected empty payload", "peerCount": 2}
2020-06-30T08:59:40.673Z INFO new peer connected {"addr": "172.200.0.3:44950", "peerCount": 3}
2020-06-30T08:59:40.673Z INFO new peer connected {"addr": "172.200.0.3:20335", "peerCount": 4}
2020-06-30T08:59:40.677Z INFO node reached synchronized state, starting consensus
2020-06-30T08:59:40.677Z INFO started protocol {"addr": "172.200.0.3:44950", "userAgent": "/NEO-GO:/", "startHeight": 0, "id": 2658713129}
2020-06-30T08:59:40.689Z WARN peer disconnected {"addr": "172.200.0.3:20335", "reason": "already connected", "peerCount": 3}
2020-06-30T08:59:40.697Z INFO blockchain persist completed {"persistedBlocks": 0, "persistedKeys": 23, "headerHeight": 0, "blockHeight": 0, "took": "243.634µs"}
2020-06-30T08:59:41.057Z INFO initializing dbft {"height": 1, "view": 0, "index": 0, "role": "Backup"}
2020-06-30T08:59:41.057Z DPANIC invalid message
2020-06-30T08:59:41.058Z DPANIC invalid message
```
Reason: payload wasn't decoded as payload.message isn't null anymore.
Fixed.
2020-06-30 09:00:41 +00:00
|
|
|
if cp.message.payload == nil {
|
2020-04-15 15:56:45 +00:00
|
|
|
if err := cp.decodeData(); err != nil {
|
|
|
|
log.Debug("can't decode payload data")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
s.messages <- *cp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) OnTransaction(tx *transaction.Transaction) {
|
|
|
|
if s.dbft != nil {
|
|
|
|
s.transactions <- tx
|
|
|
|
}
|
2019-11-08 15:40:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayload returns payload stored in cache.
|
|
|
|
func (s *service) GetPayload(h util.Uint256) *Payload {
|
2019-11-15 10:32:40 +00:00
|
|
|
p := s.cache.Get(h)
|
|
|
|
if p == nil {
|
|
|
|
return (*Payload)(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
cp := *p.(*Payload)
|
|
|
|
|
|
|
|
return &cp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) broadcast(p payload.ConsensusPayload) {
|
2019-12-05 09:07:09 +00:00
|
|
|
if err := p.(*Payload).Sign(s.dbft.Priv.(*privateKey)); err != nil {
|
2020-01-09 14:46:08 +00:00
|
|
|
s.log.Warn("can't sign consensus payload", zap.Error(err))
|
2019-12-05 09:07:09 +00:00
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
s.cache.Add(p)
|
|
|
|
s.Config.Broadcast(p.(*Payload))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) getTx(h util.Uint256) block.Transaction {
|
|
|
|
if tx := s.txx.Get(h); tx != nil {
|
|
|
|
return tx.(*transaction.Transaction)
|
|
|
|
}
|
|
|
|
|
|
|
|
tx, _, _ := s.Config.Chain.GetTransaction(h)
|
|
|
|
|
2019-12-27 10:52:07 +00:00
|
|
|
// this is needed because in case of absent tx dBFT expects to
|
|
|
|
// get nil interface, not a nil pointer to any concrete type
|
|
|
|
if tx != nil {
|
|
|
|
return tx
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) verifyBlock(b block.Block) bool {
|
|
|
|
coreb := &b.(*neoBlock).Block
|
2020-08-03 16:27:32 +00:00
|
|
|
|
2020-08-19 16:38:50 +00:00
|
|
|
if s.Chain.BlockHeight() >= coreb.Index {
|
|
|
|
s.log.Warn("proposed block has already outdated")
|
|
|
|
return false
|
|
|
|
}
|
2020-12-16 10:24:49 +00:00
|
|
|
if s.lastTimestamp >= coreb.Timestamp {
|
|
|
|
s.log.Warn("proposed block has small timestamp",
|
|
|
|
zap.Uint64("ts", coreb.Timestamp),
|
|
|
|
zap.Uint64("last", s.lastTimestamp))
|
|
|
|
return false
|
|
|
|
}
|
2020-11-27 10:55:48 +00:00
|
|
|
maxBlockSize := int(s.Chain.GetPolicer().GetMaxBlockSize())
|
2020-08-03 16:27:32 +00:00
|
|
|
size := io.GetVarSize(coreb)
|
|
|
|
if size > maxBlockSize {
|
|
|
|
s.log.Warn("proposed block size exceeds policy max block size",
|
|
|
|
zap.Int("max size allowed", maxBlockSize),
|
|
|
|
zap.Int("block size", size))
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
var fee int64
|
2020-11-27 10:55:48 +00:00
|
|
|
var pool = mempool.New(len(coreb.Transactions), 0)
|
2020-08-19 16:27:15 +00:00
|
|
|
var mainPool = s.Chain.GetMemPool()
|
2019-11-15 10:32:40 +00:00
|
|
|
for _, tx := range coreb.Transactions {
|
2020-08-19 16:27:15 +00:00
|
|
|
var err error
|
|
|
|
|
2020-08-03 16:27:32 +00:00
|
|
|
fee += tx.SystemFee
|
2020-08-19 16:27:15 +00:00
|
|
|
if mainPool.ContainsKey(tx.Hash()) {
|
|
|
|
err = pool.Add(tx, s.Chain)
|
|
|
|
if err == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err = s.Chain.PoolTx(tx, pool)
|
|
|
|
}
|
|
|
|
if err != nil {
|
2020-04-20 07:57:09 +00:00
|
|
|
s.log.Warn("invalid transaction in proposed block",
|
|
|
|
zap.Stringer("hash", tx.Hash()),
|
|
|
|
zap.Error(err))
|
2019-11-15 10:32:40 +00:00
|
|
|
return false
|
|
|
|
}
|
2020-08-19 16:38:50 +00:00
|
|
|
if s.Chain.BlockHeight() >= coreb.Index {
|
|
|
|
s.log.Warn("proposed block has already outdated")
|
|
|
|
return false
|
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-27 10:55:48 +00:00
|
|
|
maxBlockSysFee := s.Chain.GetPolicer().GetMaxBlockSystemFee()
|
2020-08-03 16:27:32 +00:00
|
|
|
if fee > maxBlockSysFee {
|
|
|
|
s.log.Warn("proposed block system fee exceeds policy max block system fee",
|
|
|
|
zap.Int("max system fee allowed", int(maxBlockSysFee)),
|
|
|
|
zap.Int("block system fee", int(fee)))
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
func (s *service) verifyRequest(p payload.ConsensusPayload) error {
|
|
|
|
req := p.GetPrepareRequest().(*prepareRequest)
|
2020-11-17 12:57:50 +00:00
|
|
|
if s.stateRootEnabled {
|
|
|
|
sr, err := s.Chain.GetStateRoot(s.dbft.BlockIndex - 1)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
} else if sr.Root != req.stateRoot {
|
|
|
|
return fmt.Errorf("state root mismatch: %s != %s", sr.Root, req.stateRoot)
|
|
|
|
}
|
|
|
|
}
|
consensus: prevent synchronization stalls
When CN is not up to date with the network is synchonizes blocks first and
only then starts consensus process. But while synchronizing it receives
consensus payloads and tries to process them even though messages reader
routine is not started yet. This leads to lots of goroutines waiting to send
their messages:
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639919 [chan send, 4 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc005bd7680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc00507d170, 0xc005bdd560, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc00507d170)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 1639181 [chan send, 10 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc013bb6600)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc01361ee10, 0xc01342c780, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc01361ee10)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Jun 25 23:55:53 nodoka neo-go[32733]: goroutine 39454 [chan send, 32 minutes]:
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/consensus.(*service).OnPayload(0xc0000ecb40, 0xc014fea680)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/consensus/consensus.go:329 +0x31b
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleConsensusCmd(...)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:687
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*Server).handleMessage(0xc0000ba160, 0x1053260, 0xc0140b2ea0, 0xc014fe0ed0, 0x0, 0x0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/server.go:806 +0xd58
Jun 25 23:55:53 nodoka neo-go[32733]: github.com/nspcc-dev/neo-go/pkg/network.(*TCPPeer).handleConn(0xc0140b2ea0)
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_peer.go:160 +0x294
Jun 25 23:55:53 nodoka neo-go[32733]: created by github.com/nspcc-dev/neo-go/pkg/network.(*TCPTransport).Dial
Jun 25 23:55:53 nodoka neo-go[32733]: #011/go/src/github.com/nspcc-dev/neo-go/pkg/network/tcp_transport.go:38 +0x1ad
Luckily it doesn't break synchronization completely as eventually connection
timers fire, the node breaks all connections, create new ones and these new
ones request blocks successfully until another consensus payload stalls them
too. In the end the node reaches synchronization, message processing loop
starts and releases all of these waiting goroutines, but it's better for us to
avoid this happening at all.
This also makes double-starting a no-op which is a nice property.
2020-06-26 08:19:01 +00:00
|
|
|
// Save lastProposal for getVerified().
|
|
|
|
s.lastProposal = req.transactionHashes
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-11-15 10:32:40 +00:00
|
|
|
func (s *service) processBlock(b block.Block) {
|
|
|
|
bb := &b.(*neoBlock).Block
|
2019-12-09 14:14:10 +00:00
|
|
|
bb.Script = *(s.getBlockWitness(bb))
|
2019-11-15 10:32:40 +00:00
|
|
|
|
|
|
|
if err := s.Chain.AddBlock(bb); err != nil {
|
2020-02-04 16:32:29 +00:00
|
|
|
// The block might already be added via the regular network
|
|
|
|
// interaction.
|
|
|
|
if _, errget := s.Chain.GetBlock(bb.Hash()); errget != nil {
|
|
|
|
s.log.Warn("error on add block", zap.Error(err))
|
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
2020-12-16 10:24:49 +00:00
|
|
|
if s.lastTimestamp < bb.Timestamp {
|
|
|
|
s.lastTimestamp = bb.Timestamp
|
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
2020-01-14 12:32:07 +00:00
|
|
|
func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness {
|
2019-11-15 10:32:40 +00:00
|
|
|
dctx := s.dbft.Context
|
|
|
|
pubs := convertKeys(dctx.Validators)
|
|
|
|
sigs := make(map[*keys.PublicKey][]byte)
|
|
|
|
|
|
|
|
for i := range pubs {
|
|
|
|
if p := dctx.CommitPayloads[i]; p != nil && p.ViewNumber() == dctx.ViewNumber {
|
|
|
|
sigs[pubs[i]] = p.GetCommit().Signature()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m := s.dbft.Context.M()
|
|
|
|
verif, err := smartcontract.CreateMultiSigRedeemScript(m, pubs)
|
|
|
|
if err != nil {
|
2020-01-09 14:46:08 +00:00
|
|
|
s.log.Warn("can't create multisig redeem script", zap.Error(err))
|
2019-11-15 10:32:40 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(keys.PublicKeys(pubs))
|
|
|
|
|
2020-04-21 13:45:48 +00:00
|
|
|
buf := io.NewBufBinWriter()
|
2019-11-15 10:32:40 +00:00
|
|
|
for i, j := 0, 0; i < len(pubs) && j < m; i++ {
|
|
|
|
if sig, ok := sigs[pubs[i]]; ok {
|
2020-04-21 13:45:48 +00:00
|
|
|
emit.Bytes(buf.BinWriter, sig)
|
2019-11-15 10:32:40 +00:00
|
|
|
j++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &transaction.Witness{
|
2020-04-21 13:45:48 +00:00
|
|
|
InvocationScript: buf.Bytes(),
|
2019-11-15 10:32:40 +00:00
|
|
|
VerificationScript: verif,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *service) getBlock(h util.Uint256) block.Block {
|
|
|
|
b, err := s.Chain.GetBlock(h)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &neoBlock{Block: *b}
|
|
|
|
}
|
|
|
|
|
2020-06-16 11:59:09 +00:00
|
|
|
func (s *service) getVerifiedTx() []block.Transaction {
|
2019-11-15 10:32:40 +00:00
|
|
|
pool := s.Config.Chain.GetMemPool()
|
2020-01-14 11:34:09 +00:00
|
|
|
|
2020-06-05 16:01:10 +00:00
|
|
|
var txx []*transaction.Transaction
|
2020-01-14 11:34:09 +00:00
|
|
|
|
|
|
|
if s.dbft.ViewNumber > 0 {
|
2020-06-05 16:01:10 +00:00
|
|
|
txx = make([]*transaction.Transaction, 0, len(s.lastProposal))
|
2020-01-14 11:34:09 +00:00
|
|
|
for i := range s.lastProposal {
|
2020-06-05 16:01:10 +00:00
|
|
|
if tx, ok := pool.TryGetValue(s.lastProposal[i]); ok {
|
|
|
|
txx = append(txx, tx)
|
2020-01-14 11:34:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(txx) < len(s.lastProposal)/2 {
|
|
|
|
txx = pool.GetVerifiedTransactions()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
txx = pool.GetVerifiedTransactions()
|
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
|
2020-02-18 17:16:38 +00:00
|
|
|
if len(txx) > 0 {
|
|
|
|
txx = s.Config.Chain.ApplyPolicyToTxSet(txx)
|
|
|
|
}
|
|
|
|
|
2020-04-22 17:42:38 +00:00
|
|
|
res := make([]block.Transaction, len(txx))
|
2019-11-29 12:40:21 +00:00
|
|
|
for i := range txx {
|
2020-06-05 16:01:10 +00:00
|
|
|
res[i] = txx[i]
|
2020-02-14 16:21:24 +00:00
|
|
|
}
|
2019-11-15 10:32:40 +00:00
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2020-07-11 10:10:57 +00:00
|
|
|
func (s *service) getValidators(txes ...block.Transaction) []crypto.PublicKey {
|
2020-02-28 08:10:01 +00:00
|
|
|
var (
|
|
|
|
pKeys []*keys.PublicKey
|
|
|
|
err error
|
|
|
|
)
|
2020-07-11 10:10:57 +00:00
|
|
|
if txes == nil {
|
|
|
|
pKeys, err = s.Chain.GetNextBlockValidators()
|
|
|
|
} else {
|
|
|
|
pKeys, err = s.Chain.GetValidators()
|
|
|
|
}
|
2020-02-28 08:10:01 +00:00
|
|
|
if err != nil {
|
|
|
|
s.log.Error("error while trying to get validators", zap.Error(err))
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pubs := make([]crypto.PublicKey, len(pKeys))
|
|
|
|
for i := range pKeys {
|
|
|
|
pubs[i] = &publicKey{PublicKey: pKeys[i]}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pubs
|
|
|
|
}
|
|
|
|
|
2020-07-11 09:32:53 +00:00
|
|
|
func (s *service) getConsensusAddress(validators ...crypto.PublicKey) util.Uint160 {
|
|
|
|
return util.Uint160{}
|
2019-11-15 10:32:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func convertKeys(validators []crypto.PublicKey) (pubs []*keys.PublicKey) {
|
|
|
|
pubs = make([]*keys.PublicKey, len(validators))
|
|
|
|
for i, k := range validators {
|
|
|
|
pubs[i] = k.(*publicKey).PublicKey
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2019-11-08 15:40:21 +00:00
|
|
|
}
|
2020-04-23 08:52:31 +00:00
|
|
|
|
2020-06-18 09:00:51 +00:00
|
|
|
func (s *service) newBlockFromContext(ctx *dbft.Context) block.Block {
|
2020-04-23 08:52:31 +00:00
|
|
|
block := new(neoBlock)
|
|
|
|
if ctx.TransactionHashes == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-18 09:00:51 +00:00
|
|
|
block.Block.Network = s.network
|
2020-07-11 12:22:14 +00:00
|
|
|
block.Block.Timestamp = ctx.Timestamp / nsInMs
|
2020-04-23 08:52:31 +00:00
|
|
|
block.Block.Index = ctx.BlockIndex
|
2020-11-17 12:57:50 +00:00
|
|
|
if s.stateRootEnabled {
|
|
|
|
sr, err := s.Chain.GetStateRoot(ctx.BlockIndex - 1)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
block.StateRootEnabled = true
|
|
|
|
block.PrevStateRoot = sr.Root
|
|
|
|
}
|
2020-07-11 09:32:53 +00:00
|
|
|
|
2020-11-09 12:11:51 +00:00
|
|
|
var validators keys.PublicKeys
|
|
|
|
var err error
|
|
|
|
if native.ShouldUpdateCommittee(ctx.BlockIndex, s.Chain) {
|
|
|
|
validators, err = s.Chain.GetValidators()
|
|
|
|
} else {
|
|
|
|
validators, err = s.Chain.GetNextBlockValidators()
|
|
|
|
}
|
2020-07-11 09:32:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-10 15:49:48 +00:00
|
|
|
script, err := smartcontract.CreateMultiSigRedeemScript(s.dbft.Context.M(), validators)
|
2020-07-11 09:32:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
block.Block.NextConsensus = crypto.Hash160(script)
|
2020-04-23 08:52:31 +00:00
|
|
|
block.Block.PrevHash = ctx.PrevHash
|
|
|
|
block.Block.Version = ctx.Version
|
|
|
|
block.Block.ConsensusData.Nonce = ctx.Nonce
|
|
|
|
|
|
|
|
primaryIndex := uint32(ctx.PrimaryIndex)
|
|
|
|
block.Block.ConsensusData.PrimaryIndex = primaryIndex
|
|
|
|
|
2020-06-25 08:16:42 +00:00
|
|
|
hashes := make([]util.Uint256, len(ctx.TransactionHashes)+1)
|
|
|
|
hashes[0] = block.Block.ConsensusData.Hash()
|
|
|
|
copy(hashes[1:], ctx.TransactionHashes)
|
2020-09-15 15:38:15 +00:00
|
|
|
block.Block.MerkleRoot = hash.CalcMerkleRoot(hashes)
|
2020-06-25 08:16:42 +00:00
|
|
|
|
2020-04-23 08:52:31 +00:00
|
|
|
return block
|
|
|
|
}
|