lotus/chain/gen/mining.go
Raúl Kripalani 3795cc2bd2 segregate chain and state blockstores.
This paves the way for better object lifetime management.

Concretely, it makes it possible to:
- have different stores backing chain and state data.
- having the same datastore library, but using different parameters.
- attach different caching layers/policies to each class of data, e.g.
  sizing caches differently.
- specifying different retention policies for chain and state data.

This separation is important because:
- access patterns/frequency of chain and state data are different.
- state is derivable from chain, so one could never expunge the chain
  store, and only retain state objects reachable from the last finality
  in the state store.
2021-02-28 22:49:44 +00:00

179 lines
4.4 KiB
Go

package gen
import (
"context"
"github.com/filecoin-project/go-state-types/crypto"
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
)
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w api.WalletAPI, bt *api.BlockTemplate) (*types.FullBlock, error) {
pts, err := sm.ChainStore().LoadTipSet(bt.Parents)
if err != nil {
return nil, xerrors.Errorf("failed to load parent tipset: %w", err)
}
st, recpts, err := sm.TipSetState(ctx, pts)
if err != nil {
return nil, xerrors.Errorf("failed to load tipset state: %w", err)
}
_, lbst, err := stmgr.GetLookbackTipSetForRound(ctx, sm, pts, bt.Epoch)
if err != nil {
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
}
worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, lbst, bt.Miner)
if err != nil {
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
}
next := &types.BlockHeader{
Miner: bt.Miner,
Parents: bt.Parents.Cids(),
Ticket: bt.Ticket,
ElectionProof: bt.Eproof,
BeaconEntries: bt.BeaconValues,
Height: bt.Epoch,
Timestamp: bt.Timestamp,
WinPoStProof: bt.WinningPoStProof,
ParentStateRoot: st,
ParentMessageReceipts: recpts,
}
var blsMessages []*types.Message
var secpkMessages []*types.SignedMessage
var blsMsgCids, secpkMsgCids []cid.Cid
var blsSigs []crypto.Signature
for _, msg := range bt.Messages {
if msg.Signature.Type == crypto.SigTypeBLS {
blsSigs = append(blsSigs, msg.Signature)
blsMessages = append(blsMessages, &msg.Message)
c, err := sm.ChainStore().PutMessage(&msg.Message)
if err != nil {
return nil, err
}
blsMsgCids = append(blsMsgCids, c)
} else {
c, err := sm.ChainStore().PutMessage(msg)
if err != nil {
return nil, err
}
secpkMsgCids = append(secpkMsgCids, c)
secpkMessages = append(secpkMessages, msg)
}
}
store := sm.ChainStore().ActorStore(ctx)
blsmsgroot, err := toArray(store, blsMsgCids)
if err != nil {
return nil, xerrors.Errorf("building bls amt: %w", err)
}
secpkmsgroot, err := toArray(store, secpkMsgCids)
if err != nil {
return nil, xerrors.Errorf("building secpk amt: %w", err)
}
mmcid, err := store.Put(store.Context(), &types.MsgMeta{
BlsMessages: blsmsgroot,
SecpkMessages: secpkmsgroot,
})
if err != nil {
return nil, err
}
next.Messages = mmcid
aggSig, err := aggregateSignatures(blsSigs)
if err != nil {
return nil, err
}
next.BLSAggregate = aggSig
pweight, err := sm.ChainStore().Weight(ctx, pts)
if err != nil {
return nil, err
}
next.ParentWeight = pweight
baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
if err != nil {
return nil, xerrors.Errorf("computing base fee: %w", err)
}
next.ParentBaseFee = baseFee
nosigbytes, err := next.SigningBytes()
if err != nil {
return nil, xerrors.Errorf("failed to get signing bytes for block: %w", err)
}
sig, err := w.WalletSign(ctx, worker, nosigbytes, api.MsgMeta{
Type: api.MTBlock,
})
if err != nil {
return nil, xerrors.Errorf("failed to sign new block: %w", err)
}
next.BlockSig = sig
fullBlock := &types.FullBlock{
Header: next,
BlsMessages: blsMessages,
SecpkMessages: secpkMessages,
}
return fullBlock, nil
}
func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) {
sigsS := make([]ffi.Signature, len(sigs))
for i := 0; i < len(sigs); i++ {
copy(sigsS[i][:], sigs[i].Data[:ffi.SignatureBytes])
}
aggSig := ffi.Aggregate(sigsS)
if aggSig == nil {
if len(sigs) > 0 {
return nil, xerrors.Errorf("bls.Aggregate returned nil with %d signatures", len(sigs))
}
zeroSig := ffi.CreateZeroSignature()
// Note: for blst this condition should not happen - nil should not
// be returned
return &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: zeroSig[:],
}, nil
}
return &crypto.Signature{
Type: crypto.SigTypeBLS,
Data: aggSig[:],
}, nil
}
func toArray(store blockadt.Store, cids []cid.Cid) (cid.Cid, error) {
arr := blockadt.MakeEmptyArray(store)
for i, c := range cids {
oc := cbg.CborCid(c)
if err := arr.Set(uint64(i), &oc); err != nil {
return cid.Undef, err
}
}
return arr.Root()
}