2020-08-05 17:11:14 +00:00
|
|
|
package consensus
|
2020-10-21 19:54:40 +00:00
|
|
|
|
|
|
|
import (
|
2020-11-15 13:46:58 +00:00
|
|
|
"math/big"
|
2020-11-20 21:29:30 +00:00
|
|
|
"sync"
|
|
|
|
|
2020-12-04 18:30:03 +00:00
|
|
|
"github.com/Secured-Finance/dione/cache"
|
2020-12-02 13:42:02 +00:00
|
|
|
|
2021-03-05 19:29:09 +00:00
|
|
|
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
2020-12-02 13:42:02 +00:00
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
"github.com/Secured-Finance/dione/consensus/types"
|
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2020-10-21 19:54:40 +00:00
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
"github.com/Secured-Finance/dione/ethclient"
|
|
|
|
"github.com/sirupsen/logrus"
|
2020-10-21 19:54:40 +00:00
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
"github.com/Secured-Finance/dione/pubsub"
|
2020-11-20 21:29:30 +00:00
|
|
|
types2 "github.com/Secured-Finance/dione/types"
|
2020-10-21 19:54:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type PBFTConsensusManager struct {
|
2020-11-20 21:29:30 +00:00
|
|
|
psb *pubsub.PubSubRouter
|
|
|
|
minApprovals int
|
|
|
|
privKey []byte
|
|
|
|
prePreparePool *PrePreparePool
|
|
|
|
preparePool *PreparePool
|
|
|
|
commitPool *CommitPool
|
2021-03-15 20:39:52 +00:00
|
|
|
consensusMap map[string]*Consensus
|
2020-11-20 21:29:30 +00:00
|
|
|
ethereumClient *ethclient.EthereumClient
|
2020-11-27 16:16:08 +00:00
|
|
|
miner *Miner
|
2021-03-05 19:29:09 +00:00
|
|
|
eventCache cache.EventCache
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 20:39:52 +00:00
|
|
|
type Consensus struct {
|
|
|
|
mutex sync.Mutex
|
|
|
|
Finished bool
|
|
|
|
IsCurrentMinerLeader bool
|
|
|
|
Task *types2.DioneTask
|
2020-11-20 21:29:30 +00:00
|
|
|
}
|
2020-10-21 19:54:40 +00:00
|
|
|
|
2021-03-05 19:29:09 +00:00
|
|
|
func NewPBFTConsensusManager(psb *pubsub.PubSubRouter, minApprovals int, privKey []byte, ethereumClient *ethclient.EthereumClient, miner *Miner, evc cache.EventCache) *PBFTConsensusManager {
|
2020-10-21 19:54:40 +00:00
|
|
|
pcm := &PBFTConsensusManager{}
|
|
|
|
pcm.psb = psb
|
2020-11-27 16:16:08 +00:00
|
|
|
pcm.miner = miner
|
2020-12-02 13:42:02 +00:00
|
|
|
pcm.prePreparePool = NewPrePreparePool(miner, evc)
|
2020-11-15 13:46:58 +00:00
|
|
|
pcm.preparePool = NewPreparePool()
|
|
|
|
pcm.commitPool = NewCommitPool()
|
|
|
|
pcm.minApprovals = minApprovals
|
|
|
|
pcm.privKey = privKey
|
|
|
|
pcm.ethereumClient = ethereumClient
|
2021-03-05 19:29:09 +00:00
|
|
|
pcm.eventCache = evc
|
2021-03-15 20:39:52 +00:00
|
|
|
pcm.consensusMap = map[string]*Consensus{}
|
2020-11-18 19:53:52 +00:00
|
|
|
pcm.psb.Hook(types.MessageTypePrePrepare, pcm.handlePrePrepare)
|
|
|
|
pcm.psb.Hook(types.MessageTypePrepare, pcm.handlePrepare)
|
|
|
|
pcm.psb.Hook(types.MessageTypeCommit, pcm.handleCommit)
|
2020-10-21 19:54:40 +00:00
|
|
|
return pcm
|
|
|
|
}
|
|
|
|
|
2021-03-05 19:29:09 +00:00
|
|
|
func (pcm *PBFTConsensusManager) Propose(consensusID string, task types2.DioneTask, requestEvent *dioneOracle.DioneOracleNewOracleRequest) error {
|
2021-03-15 20:39:52 +00:00
|
|
|
pcm.createConsensusInfo(&task, true)
|
2020-12-02 13:42:02 +00:00
|
|
|
|
|
|
|
prePrepareMsg, err := pcm.prePreparePool.CreatePrePrepare(
|
2021-03-15 20:39:52 +00:00
|
|
|
&task,
|
2021-03-05 19:29:09 +00:00
|
|
|
requestEvent.ReqID.String(),
|
2020-12-04 18:30:03 +00:00
|
|
|
requestEvent.CallbackAddress.Bytes(),
|
|
|
|
requestEvent.CallbackMethodID[:],
|
2020-12-02 13:42:02 +00:00
|
|
|
pcm.privKey,
|
|
|
|
)
|
2020-11-15 13:46:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pcm.psb.BroadcastToServiceTopic(prePrepareMsg)
|
|
|
|
return nil
|
|
|
|
}
|
2020-11-12 14:18:30 +00:00
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
func (pcm *PBFTConsensusManager) handlePrePrepare(message *types.Message) {
|
2021-03-15 20:39:52 +00:00
|
|
|
if message.Payload.Task.Miner == pcm.miner.address {
|
|
|
|
return
|
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
if pcm.prePreparePool.IsExistingPrePrepare(message) {
|
|
|
|
logrus.Debug("received existing pre_prepare msg, dropping...")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !pcm.prePreparePool.IsValidPrePrepare(message) {
|
|
|
|
logrus.Debug("received invalid pre_prepare msg, dropping...")
|
|
|
|
return
|
|
|
|
}
|
2020-10-21 19:54:40 +00:00
|
|
|
|
2020-11-20 21:29:30 +00:00
|
|
|
pcm.prePreparePool.AddPrePrepare(message)
|
2020-11-27 16:16:08 +00:00
|
|
|
err := pcm.psb.BroadcastToServiceTopic(message)
|
2020-11-20 21:29:30 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf(err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
prepareMsg, err := pcm.preparePool.CreatePrepare(message, pcm.privKey)
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to create prepare message: %w", err)
|
|
|
|
}
|
2021-03-15 20:39:52 +00:00
|
|
|
|
|
|
|
pcm.createConsensusInfo(&message.Payload.Task, false)
|
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
pcm.psb.BroadcastToServiceTopic(prepareMsg)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
func (pcm *PBFTConsensusManager) handlePrepare(message *types.Message) {
|
2020-11-15 13:46:58 +00:00
|
|
|
if pcm.preparePool.IsExistingPrepare(message) {
|
|
|
|
logrus.Debug("received existing prepare msg, dropping...")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !pcm.preparePool.IsValidPrepare(message) {
|
|
|
|
logrus.Debug("received invalid prepare msg, dropping...")
|
2020-10-21 19:54:40 +00:00
|
|
|
return
|
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
|
|
|
|
pcm.preparePool.AddPrepare(message)
|
2020-11-27 16:16:08 +00:00
|
|
|
err := pcm.psb.BroadcastToServiceTopic(message)
|
2020-11-20 21:29:30 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
|
2021-03-15 20:39:52 +00:00
|
|
|
if pcm.preparePool.PreparePoolSize(message.Payload.Task.ConsensusID) >= pcm.minApprovals {
|
2020-11-15 13:46:58 +00:00
|
|
|
commitMsg, err := pcm.commitPool.CreateCommit(message, pcm.privKey)
|
2020-10-21 19:54:40 +00:00
|
|
|
if err != nil {
|
2020-11-15 13:46:58 +00:00
|
|
|
logrus.Errorf("failed to create commit message: %w", err)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
pcm.psb.BroadcastToServiceTopic(commitMsg)
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-18 19:53:52 +00:00
|
|
|
func (pcm *PBFTConsensusManager) handleCommit(message *types.Message) {
|
2020-11-15 13:46:58 +00:00
|
|
|
if pcm.commitPool.IsExistingCommit(message) {
|
|
|
|
logrus.Debug("received existing commit msg, dropping...")
|
2020-10-21 19:54:40 +00:00
|
|
|
return
|
|
|
|
}
|
2020-11-15 13:46:58 +00:00
|
|
|
if !pcm.commitPool.IsValidCommit(message) {
|
|
|
|
logrus.Debug("received invalid commit msg, dropping...")
|
2020-10-22 14:37:31 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
pcm.commitPool.AddCommit(message)
|
2020-11-27 16:16:08 +00:00
|
|
|
err := pcm.psb.BroadcastToServiceTopic(message)
|
2020-11-20 21:29:30 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf(err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-10-22 14:37:31 +00:00
|
|
|
|
2020-11-15 13:46:58 +00:00
|
|
|
consensusMsg := message.Payload
|
2021-03-15 20:39:52 +00:00
|
|
|
if pcm.commitPool.CommitSize(consensusMsg.Task.ConsensusID) >= pcm.minApprovals {
|
|
|
|
info := pcm.consensusMap[consensusMsg.Task.ConsensusID]
|
|
|
|
info.mutex.Lock()
|
|
|
|
defer info.mutex.Unlock()
|
|
|
|
if info.Finished {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if info.IsCurrentMinerLeader {
|
|
|
|
logrus.Infof("Submitting on-chain result for consensus ID: %s", consensusMsg.Task.ConsensusID)
|
|
|
|
reqID, ok := new(big.Int).SetString(consensusMsg.Task.RequestID, 10)
|
2020-11-15 13:46:58 +00:00
|
|
|
if !ok {
|
2021-03-15 20:39:52 +00:00
|
|
|
logrus.Errorf("Failed to parse request ID: %v", consensusMsg.Task.RequestID)
|
2020-11-15 13:46:58 +00:00
|
|
|
}
|
2021-03-15 20:39:52 +00:00
|
|
|
callbackAddress := common.BytesToAddress(consensusMsg.Task.CallbackAddress)
|
2021-03-05 19:29:09 +00:00
|
|
|
|
2021-03-15 20:39:52 +00:00
|
|
|
request, err := pcm.eventCache.GetOracleRequestEvent("request_" + consensusMsg.Task.RequestID)
|
2021-03-05 19:29:09 +00:00
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("Failed to get request from cache: %v", err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-04-15 21:01:27 +00:00
|
|
|
err = pcm.ethereumClient.SubmitRequestAnswer(reqID, callbackAddress, request.CallbackMethodID, request.RequestParams, request.Deadline, consensusMsg.Task.Payload)
|
2020-11-15 13:46:58 +00:00
|
|
|
if err != nil {
|
2021-03-05 19:29:09 +00:00
|
|
|
logrus.Errorf("Failed to submit on-chain result: %v", err)
|
2020-11-15 13:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 20:39:52 +00:00
|
|
|
|
|
|
|
info.Finished = true
|
2020-10-21 19:54:40 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 20:39:52 +00:00
|
|
|
|
|
|
|
func (pcm *PBFTConsensusManager) createConsensusInfo(task *types2.DioneTask, isLeader bool) {
|
2021-04-15 21:01:27 +00:00
|
|
|
if _, ok := pcm.consensusMap[task.ConsensusID]; !ok {
|
|
|
|
pcm.consensusMap[task.ConsensusID] = &Consensus{
|
|
|
|
IsCurrentMinerLeader: isLeader,
|
|
|
|
Task: task,
|
|
|
|
Finished: false,
|
|
|
|
}
|
2021-03-15 20:39:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pcm *PBFTConsensusManager) GetConsensusInfo(consensusID string) *Consensus {
|
|
|
|
c, ok := pcm.consensusMap[consensusID]
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|