113 lines
2.8 KiB
Go
113 lines
2.8 KiB
Go
package consensus
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"sync"
|
|
|
|
"github.com/Secured-Finance/dione/types"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
type Miner struct {
|
|
address address.Address
|
|
api MinerAPI
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
type MinerAPI interface {
|
|
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
|
// TODO: get miner base based on epoch;
|
|
}
|
|
|
|
type MinerBase struct {
|
|
MinerStake types.BigInt
|
|
NetworkStake types.BigInt
|
|
WorkerKey address.Address
|
|
EthWallet common.Address
|
|
PrevBeaconEntry types.BeaconEntry
|
|
BeaconEntries []types.BeaconEntry
|
|
NullRounds types.TaskEpoch
|
|
}
|
|
|
|
type MiningBase struct {
|
|
epoch types.TaskEpoch
|
|
nullRounds types.TaskEpoch
|
|
}
|
|
|
|
func NewMinerBase(minerStake, networkStake types.BigInt, minerWallet address.Address,
|
|
minerEthWallet common.Address, prev types.BeaconEntry, entries []types.BeaconEntry) *MinerBase {
|
|
return &MinerBase{
|
|
MinerStake: minerStake,
|
|
NetworkStake: networkStake,
|
|
WorkerKey: minerWallet,
|
|
EthWallet: minerEthWallet,
|
|
PrevBeaconEntry: prev,
|
|
BeaconEntries: entries,
|
|
}
|
|
}
|
|
|
|
func NewMiningBase() *MiningBase {
|
|
return &MiningBase{
|
|
nullRounds: 0,
|
|
}
|
|
}
|
|
|
|
// Start, Stop mining functions
|
|
|
|
func (m *Miner) MineTask(ctx context.Context, base *MiningBase, mb *MinerBase) (*types.DioneTask, error) {
|
|
round := base.epoch + base.nullRounds + 1
|
|
logrus.Debug("attempting to mine the task at epoch: ", round)
|
|
|
|
prevEntry := mb.PrevBeaconEntry
|
|
|
|
ticket, err := m.computeTicket(ctx, &prevEntry, base, mb)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("scratching ticket failed: %w", err)
|
|
}
|
|
|
|
winner, err := IsRoundWinner(ctx, round, m.address, prevEntry, mb, m.api)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
|
|
}
|
|
|
|
if winner == nil {
|
|
return nil, nil
|
|
}
|
|
return &types.DioneTask{
|
|
Miner: m.address,
|
|
Ticket: ticket,
|
|
ElectionProof: winner,
|
|
BeaconEntries: mb.BeaconEntries,
|
|
// TODO: signature
|
|
Epoch: round,
|
|
}, nil
|
|
}
|
|
|
|
func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, mb *MinerBase) (*types.Ticket, error) {
|
|
buf := new(bytes.Buffer)
|
|
if err := m.address.MarshalCBOR(buf); err != nil {
|
|
return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
|
|
}
|
|
|
|
round := base.epoch + base.nullRounds + 1
|
|
|
|
input, err := DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-types.TicketRandomnessLookback, buf.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
vrfOut, err := ComputeVRF(ctx, m.api.WalletSign, mb.WorkerKey, input)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.Ticket{
|
|
VRFProof: vrfOut,
|
|
}, nil
|
|
}
|