lotus/chain/gen/gen.go

279 lines
6.0 KiB
Go
Raw Normal View History

2019-07-25 22:15:33 +00:00
package gen
import (
"bytes"
2019-07-25 22:15:33 +00:00
"context"
2019-07-30 13:20:40 +00:00
"sync/atomic"
2019-07-25 22:15:33 +00:00
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-car"
offline "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-merkledag"
2019-08-15 18:45:32 +00:00
"golang.org/x/xerrors"
"github.com/filecoin-project/go-lotus/build"
2019-07-25 22:15:33 +00:00
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/wallet"
"github.com/filecoin-project/go-lotus/lib/vdf"
2019-07-25 22:15:33 +00:00
"github.com/filecoin-project/go-lotus/node/repo"
2019-07-26 12:19:27 +00:00
2019-07-25 22:15:33 +00:00
block "github.com/ipfs/go-block-format"
2019-07-26 12:19:27 +00:00
"github.com/ipfs/go-cid"
2019-07-25 22:15:33 +00:00
blockstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log"
)
var log = logging.Logger("gen")
const msgsPerBlock = 20
2019-07-30 13:20:40 +00:00
2019-07-25 22:15:33 +00:00
type ChainGen struct {
accounts []address.Address
msgsPerBlock int
bs blockstore.Blockstore
cs *store.ChainStore
2019-07-30 13:20:40 +00:00
genesis *types.BlockHeader
2019-07-25 22:15:33 +00:00
curBlock *types.FullBlock
2019-07-30 13:20:40 +00:00
w *wallet.Wallet
miner address.Address
2019-08-15 02:30:21 +00:00
mworker 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
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 {
// change to error for stacktraces, don't commit with that pls
2019-07-31 07:13:49 +00:00
log.Warnf("Get failed: %s %s", c, err)
2019-07-25 22:15:33 +00:00
return nil, err
}
return b, nil
}
func NewGenerator() (*ChainGen, error) {
mr := repo.NewMemory(nil)
lr, err := mr.Lock()
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
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
}
2019-08-15 02:30:21 +00:00
worker, err := w.GenerateKey(types.KTBLS)
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 worker key: %w", err)
2019-07-25 22:15:33 +00:00
}
banker, err := w.GenerateKey(types.KTSecp256k1)
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 {
receievers[r], err = w.GenerateKey(types.KTBLS)
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
}
}
2019-08-15 02:30:21 +00:00
minercfg := &GenMinerCfg{
Worker: worker,
Owner: worker,
}
2019-07-25 22:15:33 +00:00
genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{
2019-08-15 02:30:21 +00:00
worker: types.NewInt(50000),
2019-07-25 22:15:33 +00:00
banker: types.NewInt(90000000),
}, minercfg, 100000)
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
}
cs := store.NewChainStore(bs, ds)
genfb := &types.FullBlock{Header: genb.Genesis}
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
}
if minercfg.MinerAddr == address.Undef {
return nil, xerrors.Errorf("MakeGenesisBlock failed to set miner address")
}
2019-07-25 22:15:33 +00:00
gen := &ChainGen{
bs: bs,
cs: cs,
msgsPerBlock: msgsPerBlock,
genesis: genb.Genesis,
2019-07-30 13:20:40 +00:00
w: w,
2019-08-15 02:30:21 +00:00
miner: minercfg.MinerAddr,
mworker: worker,
2019-07-30 13:20:40 +00:00
banker: banker,
receivers: receievers,
curBlock: genfb,
2019-07-29 19:34:09 +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
}
func (cg *ChainGen) Genesis() *types.BlockHeader {
return cg.genesis
}
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)
if err := car.WriteCar(context.TODO(), dserv, []cid.Cid{cg.Genesis().Cid()}, out); err != nil {
return nil, err
}
return out.Bytes(), nil
}
2019-08-16 04:40:59 +00:00
func (cg *ChainGen) nextBlockProof(ctx context.Context) (address.Address, types.ElectionProof, []*types.Ticket, error) {
2019-08-16 04:40:59 +00:00
ticks := cg.curBlock.Header.Tickets
lastTicket := ticks[len(ticks)-1]
vrfout, err := ComputeVRF(ctx, cg.w.Sign, cg.mworker, lastTicket.VDFResult)
if err != nil {
return address.Undef, nil, nil, err
}
out, proof, err := vdf.Run(vrfout)
if err != nil {
return address.Undef, nil, nil, err
}
2019-08-15 02:30:21 +00:00
tick := &types.Ticket{
2019-08-16 04:40:59 +00:00
VRFProof: vrfout,
VDFProof: proof,
VDFResult: out,
2019-08-15 02:30:21 +00:00
}
2019-08-15 02:30:21 +00:00
return cg.miner, []byte("cat in a box"), []*types.Ticket{tick}, nil
2019-07-25 22:15:33 +00:00
}
func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error) {
2019-08-16 04:40:59 +00:00
miner, proof, tickets, err := cg.nextBlockProof(context.TODO())
2019-07-25 22:15:33 +00:00
if err != nil {
return nil, nil, err
2019-07-25 22:15:33 +00:00
}
2019-07-30 13:20:40 +00:00
// make some transfers from banker
msgs := make([]*types.SignedMessage, cg.msgsPerBlock)
for m := range msgs {
msg := types.Message{
To: cg.receivers[m],
From: cg.banker,
Nonce: atomic.AddUint64(&cg.bankerNonce, 1) - 1,
Value: types.NewInt(uint64(m + 1)),
Method: 0,
GasLimit: types.NewInt(10000),
GasPrice: types.NewInt(0),
}
unsigned, err := msg.Serialize()
if err != nil {
return nil, nil, err
2019-07-30 13:20:40 +00:00
}
2019-08-16 04:40:59 +00:00
sig, err := cg.w.Sign(context.TODO(), cg.banker, unsigned)
2019-07-30 13:20:40 +00:00
if err != nil {
return nil, nil, err
2019-07-30 13:20:40 +00:00
}
msgs[m] = &types.SignedMessage{
Message: msg,
Signature: *sig,
}
if _, err := cg.cs.PutMessage(msgs[m]); err != nil {
return nil, nil, err
2019-07-30 13:20:40 +00:00
}
}
// create block
2019-07-25 22:15:33 +00:00
parents, err := types.NewTipSet([]*types.BlockHeader{cg.curBlock.Header})
if err != nil {
return nil, nil, err
2019-07-25 22:15:33 +00:00
}
ts := parents.MinTimestamp() + (uint64(len(tickets)) * build.BlockDelay)
fblk, err := MinerCreateBlock(context.TODO(), cg.cs, cg.w, miner, parents, tickets, proof, msgs, ts)
2019-07-25 22:15:33 +00:00
if err != nil {
return nil, nil, err
2019-07-25 22:15:33 +00:00
}
2019-07-26 12:19:27 +00:00
if err := cg.cs.AddBlock(fblk.Header); err != nil {
return nil, nil, err
2019-07-26 12:19:27 +00:00
}
2019-07-25 22:15:33 +00:00
cg.curBlock = fblk
return fblk, 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
}