2019-07-25 22:15:33 +00:00
|
|
|
package gen
|
|
|
|
|
|
|
|
import (
|
2019-07-30 11:45:48 +00:00
|
|
|
"bytes"
|
2019-07-25 22:15:33 +00:00
|
|
|
"context"
|
2019-09-06 06:26:02 +00:00
|
|
|
"fmt"
|
2019-11-29 03:38:18 +00:00
|
|
|
"io/ioutil"
|
2019-07-30 13:20:40 +00:00
|
|
|
"sync/atomic"
|
2019-07-25 22:15:33 +00:00
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-02-19 19:26:11 +00:00
|
|
|
commcid "github.com/filecoin-project/go-fil-commcid"
|
2020-02-08 02:18:32 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
2020-02-12 23:52:36 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/crypto"
|
2020-03-06 05:30:47 +00:00
|
|
|
"github.com/filecoin-project/specs-storage/storage"
|
2020-01-30 23:48:25 +00:00
|
|
|
block "github.com/ipfs/go-block-format"
|
2019-07-30 11:45:48 +00:00
|
|
|
"github.com/ipfs/go-blockservice"
|
|
|
|
"github.com/ipfs/go-car"
|
2020-01-30 23:48:25 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
2019-07-30 11:45:48 +00:00
|
|
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
2020-02-23 20:00:47 +00:00
|
|
|
format "github.com/ipfs/go-ipld-format"
|
2020-01-30 23:48:25 +00:00
|
|
|
logging "github.com/ipfs/go-log/v2"
|
2019-07-30 11:45:48 +00:00
|
|
|
"github.com/ipfs/go-merkledag"
|
2020-03-26 19:34:38 +00:00
|
|
|
"github.com/minio/blake2b-simd"
|
|
|
|
"go.opencensus.io/trace"
|
|
|
|
"golang.org/x/xerrors"
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
|
|
"github.com/filecoin-project/lotus/build"
|
2020-02-11 20:48:03 +00:00
|
|
|
genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
|
|
|
"github.com/filecoin-project/lotus/chain/store"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-01-30 23:48:25 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/vm"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/wallet"
|
2019-11-29 03:38:18 +00:00
|
|
|
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
|
|
|
"github.com/filecoin-project/lotus/genesis"
|
2020-01-30 23:48:25 +00:00
|
|
|
"github.com/filecoin-project/lotus/lib/sigs"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/repo"
|
2020-03-27 23:00:21 +00:00
|
|
|
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
2019-07-25 22:15:33 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var log = logging.Logger("gen")
|
|
|
|
|
2019-10-08 00:28:13 +00:00
|
|
|
const msgsPerBlock = 20
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-25 22:15:33 +00:00
|
|
|
type ChainGen struct {
|
|
|
|
msgsPerBlock int
|
|
|
|
|
|
|
|
bs blockstore.Blockstore
|
|
|
|
|
|
|
|
cs *store.ChainStore
|
|
|
|
|
2019-09-06 06:26:02 +00:00
|
|
|
sm *stmgr.StateManager
|
|
|
|
|
|
|
|
genesis *types.BlockHeader
|
2019-10-05 23:18:39 +00:00
|
|
|
CurTipset *store.FullTipSet
|
2019-07-25 22:15:33 +00:00
|
|
|
|
2020-02-08 02:18:32 +00:00
|
|
|
Timestamper func(*types.TipSet, abi.ChainEpoch) uint64
|
2019-10-10 03:04:10 +00:00
|
|
|
|
2020-01-31 23:51:15 +00:00
|
|
|
GetMessages func(*ChainGen) ([]*types.SignedMessage, error)
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
w *wallet.Wallet
|
|
|
|
|
2019-11-21 22:21:45 +00:00
|
|
|
eppProvs map[address.Address]ElectionPoStProver
|
2019-10-05 16:04:58 +00:00
|
|
|
Miners []address.Address
|
2019-07-30 13:20:40 +00:00
|
|
|
receivers []address.Address
|
|
|
|
banker address.Address
|
|
|
|
bankerNonce uint64
|
2019-07-29 19:34:09 +00:00
|
|
|
|
2019-07-30 11:45:48 +00:00
|
|
|
r repo.Repo
|
2019-07-29 19:34:09 +00:00
|
|
|
lr repo.LockedRepo
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type mybs struct {
|
|
|
|
blockstore.Blockstore
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
|
|
|
b, err := m.Blockstore.Get(c)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGenerator() (*ChainGen, error) {
|
|
|
|
mr := repo.NewMemory(nil)
|
2019-11-12 17:59:38 +00:00
|
|
|
lr, err := mr.Lock(repo.StorageMiner)
|
2019-07-25 22:15:33 +00:00
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("taking mem-repo lock failed: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-07-29 19:34:09 +00:00
|
|
|
ds, err := lr.Datastore("/metadata")
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("failed to get metadata datastore: %w", err)
|
2019-07-29 19:34:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bds, err := lr.Datastore("/blocks")
|
2019-07-25 22:15:33 +00:00
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("failed to get blocks datastore: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
2019-07-29 19:34:09 +00:00
|
|
|
|
2019-07-30 11:45:48 +00:00
|
|
|
bs := mybs{blockstore.NewIdStore(blockstore.NewBlockstore(bds))}
|
2019-07-25 22:15:33 +00:00
|
|
|
|
|
|
|
ks, err := lr.KeyStore()
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("getting repo keystore failed: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
w, err := wallet.NewWallet(ks)
|
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("creating memrepo wallet failed: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
banker, err := w.GenerateKey(crypto.SigTypeSecp256k1)
|
2019-07-25 22:15:33 +00:00
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("failed to generate banker key: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
receievers := make([]address.Address, msgsPerBlock)
|
|
|
|
for r := range receievers {
|
2020-02-12 23:52:36 +00:00
|
|
|
receievers[r], err = w.GenerateKey(crypto.SigTypeBLS)
|
2019-07-30 13:20:40 +00:00
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("failed to generate receiver key: %w", err)
|
2019-07-30 13:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 21:41:59 +00:00
|
|
|
maddr1 := genesis2.MinerAddress(0)
|
2019-11-29 03:38:18 +00:00
|
|
|
|
|
|
|
m1temp, err := ioutil.TempDir("", "preseal")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
genm1, k1, err := seed.PreSeal(maddr1, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, 1, m1temp, []byte("some randomness"), nil)
|
2019-11-29 03:38:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-12 21:41:59 +00:00
|
|
|
maddr2 := genesis2.MinerAddress(1)
|
2019-11-29 04:04:46 +00:00
|
|
|
|
|
|
|
m2temp, err := ioutil.TempDir("", "preseal")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
genm2, k2, err := seed.PreSeal(maddr2, abi.RegisteredProof_StackedDRG2KiBPoSt, 0, 1, m2temp, []byte("some randomness"), nil)
|
2019-11-29 04:04:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-12 21:41:59 +00:00
|
|
|
mk1, err := w.Import(k1)
|
2019-11-29 04:41:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-12 21:41:59 +00:00
|
|
|
mk2, err := w.Import(k2)
|
2019-11-29 04:41:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-18 07:15:30 +00:00
|
|
|
sys := vm.Syscalls(&genFakeVerifier{})
|
2020-02-12 21:41:59 +00:00
|
|
|
|
|
|
|
tpl := genesis.Template{
|
2020-02-13 00:15:33 +00:00
|
|
|
Accounts: []genesis.Actor{
|
2020-02-12 21:41:59 +00:00
|
|
|
{
|
|
|
|
Type: genesis.TAccount,
|
|
|
|
Balance: types.FromFil(40000),
|
|
|
|
Meta: (&genesis.AccountMeta{Owner: mk1}).ActorMeta(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: genesis.TAccount,
|
|
|
|
Balance: types.FromFil(40000),
|
|
|
|
Meta: (&genesis.AccountMeta{Owner: mk2}).ActorMeta(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: genesis.TAccount,
|
|
|
|
Balance: types.FromFil(50000),
|
|
|
|
Meta: (&genesis.AccountMeta{Owner: banker}).ActorMeta(),
|
|
|
|
},
|
|
|
|
},
|
2020-02-13 00:15:33 +00:00
|
|
|
Miners: []genesis.Miner{
|
2020-02-12 21:41:59 +00:00
|
|
|
*genm1,
|
|
|
|
*genm2,
|
2019-11-29 03:38:18 +00:00
|
|
|
},
|
2020-02-12 21:41:59 +00:00
|
|
|
NetworkName: "",
|
|
|
|
Timestamp: 100000,
|
2019-09-06 20:03:28 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 21:41:59 +00:00
|
|
|
genb, err := genesis2.MakeGenesisBlock(context.TODO(), bs, sys, tpl)
|
2019-07-25 22:15:33 +00:00
|
|
|
if err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("make genesis block failed: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2020-01-13 20:47:27 +00:00
|
|
|
cs := store.NewChainStore(bs, ds, sys)
|
2019-07-25 22:15:33 +00:00
|
|
|
|
|
|
|
genfb := &types.FullBlock{Header: genb.Genesis}
|
2019-09-06 06:26:02 +00:00
|
|
|
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
|
2019-07-25 22:15:33 +00:00
|
|
|
|
2019-07-26 12:19:27 +00:00
|
|
|
if err := cs.SetGenesis(genb.Genesis); err != nil {
|
2019-08-15 18:45:32 +00:00
|
|
|
return nil, xerrors.Errorf("set genesis failed: %w", err)
|
2019-07-26 12:19:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 22:21:45 +00:00
|
|
|
mgen := make(map[address.Address]ElectionPoStProver)
|
2020-02-12 21:41:59 +00:00
|
|
|
for i := range tpl.Miners {
|
|
|
|
mgen[genesis2.MinerAddress(uint64(i))] = &eppProvider{}
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 06:26:02 +00:00
|
|
|
sm := stmgr.NewStateManager(cs)
|
|
|
|
|
2020-02-12 21:41:59 +00:00
|
|
|
miners := []address.Address{maddr1, maddr2}
|
|
|
|
|
2019-07-25 22:15:33 +00:00
|
|
|
gen := &ChainGen{
|
|
|
|
bs: bs,
|
|
|
|
cs: cs,
|
2019-09-06 06:26:02 +00:00
|
|
|
sm: sm,
|
2019-07-25 22:15:33 +00:00
|
|
|
msgsPerBlock: msgsPerBlock,
|
|
|
|
genesis: genb.Genesis,
|
2019-07-30 13:20:40 +00:00
|
|
|
w: w,
|
|
|
|
|
2020-01-31 23:51:15 +00:00
|
|
|
GetMessages: getRandomMessages,
|
2020-02-12 21:41:59 +00:00
|
|
|
Miners: miners,
|
2020-01-31 23:51:15 +00:00
|
|
|
eppProvs: mgen,
|
|
|
|
banker: banker,
|
|
|
|
receivers: receievers,
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-10-05 23:18:39 +00:00
|
|
|
CurTipset: gents,
|
2019-07-29 19:34:09 +00:00
|
|
|
|
2019-07-30 11:45:48 +00:00
|
|
|
r: mr,
|
2019-07-29 19:34:09 +00:00
|
|
|
lr: lr,
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return gen, nil
|
|
|
|
}
|
|
|
|
|
2020-01-31 23:51:15 +00:00
|
|
|
func (cg *ChainGen) SetStateManager(sm *stmgr.StateManager) {
|
|
|
|
cg.sm = sm
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *ChainGen) ChainStore() *store.ChainStore {
|
|
|
|
return cg.cs
|
|
|
|
}
|
|
|
|
|
2019-07-25 22:15:33 +00:00
|
|
|
func (cg *ChainGen) Genesis() *types.BlockHeader {
|
|
|
|
return cg.genesis
|
|
|
|
}
|
|
|
|
|
2019-07-30 11:45:48 +00:00
|
|
|
func (cg *ChainGen) GenesisCar() ([]byte, error) {
|
|
|
|
offl := offline.Exchange(cg.bs)
|
|
|
|
blkserv := blockservice.New(cg.bs, offl)
|
|
|
|
dserv := merkledag.NewDAGService(blkserv)
|
|
|
|
|
|
|
|
out := new(bytes.Buffer)
|
|
|
|
|
2020-02-21 19:27:29 +00:00
|
|
|
if err := car.WriteCarWithWalker(context.TODO(), dserv, []cid.Cid{cg.Genesis().Cid()}, out, CarWalkFunc); err != nil {
|
2019-11-21 22:21:45 +00:00
|
|
|
return nil, xerrors.Errorf("genesis car write car failed: %w", err)
|
2019-07-30 11:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return out.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
2020-02-21 19:27:29 +00:00
|
|
|
func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
|
|
|
|
for _, link := range nd.Links() {
|
|
|
|
if link.Cid.Prefix().MhType == uint64(commcid.FC_SEALED_V1) || link.Cid.Prefix().MhType == uint64(commcid.FC_UNSEALED_V1) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
out = append(out, link)
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2019-11-21 22:21:45 +00:00
|
|
|
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round int64) (*types.EPostProof, *types.Ticket, error) {
|
2020-02-23 20:00:47 +00:00
|
|
|
mc := &mca{w: cg.w, sm: cg.sm}
|
2019-09-06 06:26:02 +00:00
|
|
|
|
2020-03-19 02:42:24 +00:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
if err := m.MarshalCBOR(buf); err != nil {
|
|
|
|
return nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ticketRand, err := mc.ChainGetRandomness(ctx, pts.Key(), crypto.DomainSeparationTag_TicketProduction, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
|
2020-02-23 20:00:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2019-09-06 06:26:02 +00:00
|
|
|
|
2019-10-06 03:32:56 +00:00
|
|
|
st := pts.ParentState()
|
2019-08-16 00:17:09 +00:00
|
|
|
|
2019-10-23 17:39:14 +00:00
|
|
|
worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
2019-10-16 07:07:16 +00:00
|
|
|
return nil, nil, xerrors.Errorf("get miner worker: %w", err)
|
2019-09-06 06:26:02 +00:00
|
|
|
}
|
2019-08-16 04:40:59 +00:00
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, ticketRand)
|
2019-08-16 00:17:09 +00:00
|
|
|
if err != nil {
|
2019-10-16 07:07:16 +00:00
|
|
|
return nil, nil, xerrors.Errorf("compute VRF: %w", err)
|
2019-08-16 00:17:09 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 02:30:21 +00:00
|
|
|
tick := &types.Ticket{
|
2019-10-09 04:38:59 +00:00
|
|
|
VRFProof: vrfout,
|
2019-08-15 02:30:21 +00:00
|
|
|
}
|
2019-08-16 00:17:09 +00:00
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], mc)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
|
|
|
|
}
|
2019-12-03 21:27:07 +00:00
|
|
|
if eproofin == nil {
|
2019-09-06 06:26:02 +00:00
|
|
|
return nil, tick, nil
|
|
|
|
}
|
2019-12-03 18:25:56 +00:00
|
|
|
eproof, err := ComputeProof(ctx, cg.eppProvs[m], eproofin)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, xerrors.Errorf("computing proof: %w", err)
|
|
|
|
}
|
2019-09-06 06:26:02 +00:00
|
|
|
|
|
|
|
return eproof, tick, nil
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
type MinedTipSet struct {
|
|
|
|
TipSet *store.FullTipSet
|
|
|
|
Messages []*types.SignedMessage
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
|
2019-10-05 23:18:39 +00:00
|
|
|
mts, err := cg.NextTipSetFromMiners(cg.CurTipset.TipSet(), cg.Miners)
|
2019-10-05 16:04:58 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-10-05 23:18:39 +00:00
|
|
|
cg.CurTipset = mts.TipSet
|
2019-10-05 16:04:58 +00:00
|
|
|
return mts, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) {
|
2019-09-06 06:26:02 +00:00
|
|
|
var blks []*types.FullBlock
|
|
|
|
|
2020-01-31 23:51:15 +00:00
|
|
|
msgs, err := cg.GetMessages(cg)
|
2019-07-25 22:15:33 +00:00
|
|
|
if err != nil {
|
2019-10-16 07:07:16 +00:00
|
|
|
return nil, xerrors.Errorf("get random messages: %w", err)
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 15:53:00 +00:00
|
|
|
for round := int64(base.Height() + 1); len(blks) == 0; round++ {
|
|
|
|
for _, m := range miners {
|
|
|
|
proof, t, err := cg.nextBlockProof(context.TODO(), base, m, round)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
2019-10-02 20:27:41 +00:00
|
|
|
return nil, xerrors.Errorf("next block proof: %w", err)
|
2019-09-06 06:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if proof != nil {
|
2020-02-08 02:18:32 +00:00
|
|
|
fblk, err := cg.makeBlock(base, m, proof, t, abi.ChainEpoch(round), msgs)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
|
|
|
|
}
|
|
|
|
|
2019-11-12 10:18:46 +00:00
|
|
|
if err := cg.cs.PersistBlockHeaders(fblk.Header); err != nil {
|
2019-10-02 20:27:41 +00:00
|
|
|
return nil, xerrors.Errorf("chainstore AddBlock: %w", err)
|
2019-09-06 06:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
blks = append(blks, fblk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-05 16:04:58 +00:00
|
|
|
fts := store.NewFullTipSet(blks)
|
2019-09-06 06:26:02 +00:00
|
|
|
|
|
|
|
return &MinedTipSet{
|
2019-10-05 16:04:58 +00:00
|
|
|
TipSet: fts,
|
2019-09-06 06:26:02 +00:00
|
|
|
Messages: msgs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-02-08 02:18:32 +00:00
|
|
|
func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof *types.EPostProof, ticket *types.Ticket, height abi.ChainEpoch, msgs []*types.SignedMessage) (*types.FullBlock, error) {
|
2019-09-06 06:26:02 +00:00
|
|
|
|
2019-10-10 03:04:10 +00:00
|
|
|
var ts uint64
|
|
|
|
if cg.Timestamper != nil {
|
2019-11-19 15:53:00 +00:00
|
|
|
ts = cg.Timestamper(parents, height-parents.Height())
|
2019-10-10 03:04:10 +00:00
|
|
|
} else {
|
2020-02-08 02:18:37 +00:00
|
|
|
ts = parents.MinTimestamp() + uint64((height-parents.Height())*build.BlockDelay)
|
2019-10-10 03:04:10 +00:00
|
|
|
}
|
2019-09-06 06:26:02 +00:00
|
|
|
|
2019-11-19 15:53:00 +00:00
|
|
|
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, ticket, eproof, msgs, height, ts)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return fblk, err
|
|
|
|
}
|
|
|
|
|
2019-10-06 00:51:48 +00:00
|
|
|
// This function is awkward. It's used to deal with messages made when
|
|
|
|
// simulating forks
|
|
|
|
func (cg *ChainGen) ResyncBankerNonce(ts *types.TipSet) error {
|
|
|
|
act, err := cg.sm.GetActor(cg.banker, ts)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cg.bankerNonce = act.Nonce
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-01-31 23:51:15 +00:00
|
|
|
func (cg *ChainGen) Banker() address.Address {
|
|
|
|
return cg.banker
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cg *ChainGen) Wallet() *wallet.Wallet {
|
|
|
|
return cg.w
|
|
|
|
}
|
|
|
|
|
|
|
|
func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
|
2019-07-30 13:20:40 +00:00
|
|
|
msgs := make([]*types.SignedMessage, cg.msgsPerBlock)
|
|
|
|
for m := range msgs {
|
|
|
|
msg := types.Message{
|
2019-08-30 07:05:21 +00:00
|
|
|
To: cg.receivers[m%len(cg.receivers)],
|
2019-07-30 13:20:40 +00:00
|
|
|
From: cg.banker,
|
|
|
|
|
|
|
|
Nonce: atomic.AddUint64(&cg.bankerNonce, 1) - 1,
|
|
|
|
|
|
|
|
Value: types.NewInt(uint64(m + 1)),
|
|
|
|
|
|
|
|
Method: 0,
|
|
|
|
|
2020-03-18 20:45:37 +00:00
|
|
|
GasLimit: 10000,
|
2019-07-30 13:20:40 +00:00
|
|
|
GasPrice: types.NewInt(0),
|
|
|
|
}
|
|
|
|
|
2019-10-09 01:32:08 +00:00
|
|
|
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
|
2019-07-30 13:20:40 +00:00
|
|
|
if err != nil {
|
2019-09-03 04:36:07 +00:00
|
|
|
return nil, err
|
2019-07-30 13:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
msgs[m] = &types.SignedMessage{
|
|
|
|
Message: msg,
|
|
|
|
Signature: *sig,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 06:26:02 +00:00
|
|
|
return msgs, nil
|
2019-07-25 22:15:33 +00:00
|
|
|
}
|
2019-07-29 19:34:09 +00:00
|
|
|
|
|
|
|
func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
|
|
|
|
if err := cg.lr.Close(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cg.r, nil
|
|
|
|
}
|
2019-09-03 04:36:07 +00:00
|
|
|
|
|
|
|
type MiningCheckAPI interface {
|
2020-02-23 20:00:47 +00:00
|
|
|
ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
2019-09-03 04:36:07 +00:00
|
|
|
|
2020-04-02 01:10:28 +00:00
|
|
|
MinerGetBaseInfo(context.Context, address.Address, types.TipSetKey) (*api.MiningBaseInfo, error)
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 06:26:02 +00:00
|
|
|
type mca struct {
|
|
|
|
w *wallet.Wallet
|
|
|
|
sm *stmgr.StateManager
|
|
|
|
}
|
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) {
|
|
|
|
pts, err := mca.sm.ChainStore().LoadTipSet(tsk)
|
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("loading tipset key: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, int64(randEpoch), entropy)
|
2019-09-06 06:26:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 01:10:28 +00:00
|
|
|
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
|
|
|
|
return stmgr.MinerGetBaseInfo(ctx, mca.sm, tsk, maddr)
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*crypto.Signature, error) {
|
2019-09-06 06:26:02 +00:00
|
|
|
return mca.w.Sign(ctx, a, v)
|
|
|
|
}
|
|
|
|
|
2019-11-21 22:21:45 +00:00
|
|
|
type ElectionPoStProver interface {
|
2020-03-06 05:30:47 +00:00
|
|
|
GenerateCandidates(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]storage.PoStCandidateWithTicket, error)
|
|
|
|
ComputeProof(context.Context, []abi.SectorInfo, []byte, []storage.PoStCandidateWithTicket) ([]abi.PoStProof, error)
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
type eppProvider struct{}
|
2019-11-21 22:21:45 +00:00
|
|
|
|
2020-03-06 05:30:47 +00:00
|
|
|
func (epp *eppProvider) GenerateCandidates(ctx context.Context, _ []abi.SectorInfo, eprand abi.PoStRandomness) ([]storage.PoStCandidateWithTicket, error) {
|
|
|
|
return []storage.PoStCandidateWithTicket{
|
2019-12-02 12:51:16 +00:00
|
|
|
{
|
2020-02-27 21:45:31 +00:00
|
|
|
Candidate: abi.PoStCandidate{
|
|
|
|
RegisteredProof: abi.RegisteredProof_StackedDRG2KiBPoSt,
|
|
|
|
SectorID: abi.SectorID{Number: 1},
|
|
|
|
PartialTicket: abi.PartialTicket{},
|
|
|
|
PrivateProof: abi.PrivatePoStCandidateProof{},
|
|
|
|
ChallengeIndex: 1,
|
|
|
|
},
|
2019-11-21 22:21:45 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-03-06 05:30:47 +00:00
|
|
|
func (epp *eppProvider) ComputeProof(ctx context.Context, _ []abi.SectorInfo, eprand []byte, winners []storage.PoStCandidateWithTicket) ([]abi.PoStProof, error) {
|
2019-11-22 16:41:09 +00:00
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
return []abi.PoStProof{{
|
|
|
|
ProofBytes: []byte("valid proof"),
|
|
|
|
}}, nil
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 18:25:56 +00:00
|
|
|
type ProofInput struct {
|
2020-02-27 21:45:31 +00:00
|
|
|
sectors []abi.SectorInfo
|
2019-12-03 19:33:29 +00:00
|
|
|
hvrf []byte
|
2020-03-06 05:30:47 +00:00
|
|
|
winners []storage.PoStCandidateWithTicket
|
2019-12-03 19:33:29 +00:00
|
|
|
vrfout []byte
|
2019-12-03 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 21:27:07 +00:00
|
|
|
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (*ProofInput, error) {
|
2020-03-19 02:42:24 +00:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
if err := miner.MarshalCBOR(buf); err != nil {
|
|
|
|
return nil, xerrors.Errorf("failed to cbor marshal address: %w")
|
|
|
|
}
|
|
|
|
epostRand, err := a.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
|
2019-09-03 04:36:07 +00:00
|
|
|
if err != nil {
|
2019-12-03 21:27:07 +00:00
|
|
|
return nil, xerrors.Errorf("chain get randomness: %w", err)
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 01:10:28 +00:00
|
|
|
mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key())
|
2019-09-03 04:36:07 +00:00
|
|
|
if err != nil {
|
2020-04-02 01:10:28 +00:00
|
|
|
return nil, xerrors.Errorf("failed to get mining base info: %w", err)
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 01:10:28 +00:00
|
|
|
vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, epostRand)
|
2019-09-03 04:36:07 +00:00
|
|
|
if err != nil {
|
2019-12-03 21:27:07 +00:00
|
|
|
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 01:10:28 +00:00
|
|
|
if len(mbi.Sectors) == 0 {
|
2019-12-03 21:27:07 +00:00
|
|
|
return nil, nil
|
2019-11-29 19:14:10 +00:00
|
|
|
}
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
var sinfos []abi.SectorInfo
|
2020-04-02 01:10:28 +00:00
|
|
|
for _, s := range mbi.Sectors {
|
2020-02-29 02:02:40 +00:00
|
|
|
if s.Info.Info.RegisteredProof == 0 {
|
|
|
|
return nil, xerrors.Errorf("sector %d in proving set had registered type of zero", s.ID)
|
|
|
|
}
|
2020-02-27 21:45:31 +00:00
|
|
|
sinfos = append(sinfos, abi.SectorInfo{
|
2020-02-28 18:01:43 +00:00
|
|
|
SectorNumber: s.ID,
|
|
|
|
SealedCID: s.Info.Info.SealedCID,
|
|
|
|
RegisteredProof: s.Info.Info.RegisteredProof,
|
2019-11-25 04:45:13 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-20 04:56:13 +00:00
|
|
|
hvrf := blake2b.Sum256(vrfout)
|
2020-02-27 21:45:31 +00:00
|
|
|
candidates, err := epp.GenerateCandidates(ctx, sinfos, hvrf[:])
|
2019-11-21 22:21:45 +00:00
|
|
|
if err != nil {
|
2019-12-03 21:27:07 +00:00
|
|
|
return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err)
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
2020-03-06 05:30:47 +00:00
|
|
|
var winners []storage.PoStCandidateWithTicket
|
2019-11-21 22:21:45 +00:00
|
|
|
for _, c := range candidates {
|
2020-04-02 01:10:28 +00:00
|
|
|
if types.IsTicketWinner(c.Candidate.PartialTicket, mbi.SectorSize, uint64(len(sinfos)), mbi.NetworkPower) {
|
2019-11-21 22:21:45 +00:00
|
|
|
winners = append(winners, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no winners, sad
|
|
|
|
if len(winners) == 0 {
|
2019-12-03 21:27:07 +00:00
|
|
|
return nil, nil
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 21:27:07 +00:00
|
|
|
return &ProofInput{
|
2020-02-27 21:45:31 +00:00
|
|
|
sectors: sinfos,
|
2019-12-03 18:25:56 +00:00
|
|
|
hvrf: hvrf[:],
|
|
|
|
winners: winners,
|
|
|
|
vrfout: vrfout,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) {
|
|
|
|
proof, err := epp.ComputeProof(ctx, pi.sectors, pi.hvrf, pi.winners)
|
2019-11-21 22:21:45 +00:00
|
|
|
if err != nil {
|
2019-12-03 18:25:56 +00:00
|
|
|
return nil, xerrors.Errorf("failed to compute snark for election proof: %w", err)
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ept := types.EPostProof{
|
2020-02-27 21:45:31 +00:00
|
|
|
Proofs: proof,
|
2019-12-03 18:25:56 +00:00
|
|
|
PostRand: pi.vrfout,
|
2019-11-21 22:21:45 +00:00
|
|
|
}
|
2019-12-03 18:25:56 +00:00
|
|
|
for _, win := range pi.winners {
|
2019-12-06 08:32:57 +00:00
|
|
|
part := make([]byte, 32)
|
2020-02-27 21:45:31 +00:00
|
|
|
copy(part, win.Candidate.PartialTicket)
|
2019-11-28 12:46:56 +00:00
|
|
|
ept.Candidates = append(ept.Candidates, types.EPostTicket{
|
2019-12-06 08:32:57 +00:00
|
|
|
Partial: part,
|
2020-02-27 21:45:31 +00:00
|
|
|
SectorID: win.Candidate.SectorID.Number,
|
|
|
|
ChallengeIndex: uint64(win.Candidate.ChallengeIndex),
|
2019-11-21 22:21:45 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-12-03 18:25:56 +00:00
|
|
|
return &ept, nil
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
2019-09-03 04:36:07 +00:00
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []byte) error {
|
2019-12-02 12:51:16 +00:00
|
|
|
_, span := trace.StartSpan(ctx, "VerifyVRF")
|
2019-11-21 22:21:45 +00:00
|
|
|
defer span.End()
|
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
sig := &crypto.Signature{
|
|
|
|
Type: crypto.SigTypeBLS,
|
2019-11-21 22:21:45 +00:00
|
|
|
Data: vrfproof,
|
|
|
|
}
|
|
|
|
|
2020-01-30 23:48:25 +00:00
|
|
|
if err := sigs.Verify(sig, worker, vrfBase); err != nil {
|
2019-11-21 22:21:45 +00:00
|
|
|
return xerrors.Errorf("vrf was invalid: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-23 20:00:47 +00:00
|
|
|
func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigInput []byte) ([]byte, error) {
|
2019-11-21 22:21:45 +00:00
|
|
|
sig, err := sign(ctx, worker, sigInput)
|
2019-09-06 06:26:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-09-03 04:36:07 +00:00
|
|
|
|
2020-02-12 23:52:36 +00:00
|
|
|
if sig.Type != crypto.SigTypeBLS {
|
2019-09-06 06:26:02 +00:00
|
|
|
return nil, fmt.Errorf("miner worker address was not a BLS key")
|
|
|
|
}
|
2019-09-03 04:36:07 +00:00
|
|
|
|
2019-09-06 06:26:02 +00:00
|
|
|
return sig.Data, nil
|
2019-09-03 04:36:07 +00:00
|
|
|
}
|
2020-02-18 07:15:30 +00:00
|
|
|
|
|
|
|
type genFakeVerifier struct{}
|
|
|
|
|
2020-03-26 02:50:56 +00:00
|
|
|
var _ ffiwrapper.Verifier = (*genFakeVerifier)(nil)
|
2020-02-18 07:15:30 +00:00
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
func (m genFakeVerifier) VerifyElectionPost(ctx context.Context, pvi abi.PoStVerifyInfo) (bool, error) {
|
2020-02-18 07:15:30 +00:00
|
|
|
panic("nyi")
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
func (m genFakeVerifier) VerifySeal(svi abi.SealVerifyInfo) (bool, error) {
|
2020-02-18 07:15:30 +00:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:45:31 +00:00
|
|
|
func (m genFakeVerifier) VerifyFallbackPost(ctx context.Context, pvi abi.PoStVerifyInfo) (bool, error) {
|
2020-02-18 07:15:30 +00:00
|
|
|
panic("nyi")
|
|
|
|
}
|