genesis setup improvements

This commit is contained in:
Łukasz Magiera 2019-11-28 23:50:58 +01:00
parent 466f1d8cb9
commit cb7d15e67e
7 changed files with 210 additions and 84 deletions

View File

@ -31,12 +31,16 @@ type StorageMinerActorState struct {
PreCommittedSectors map[string]*PreCommittedSector PreCommittedSectors map[string]*PreCommittedSector
// All sectors this miner has committed. // All sectors this miner has committed.
//
// AMT[sectorID]ffi.PublicSectorInfo
Sectors cid.Cid Sectors cid.Cid
// TODO: Spec says 'StagedCommittedSectors', which one is it? // TODO: Spec says 'StagedCommittedSectors', which one is it?
// Sectors this miner is currently mining. It is only updated // Sectors this miner is currently mining. It is only updated
// when a PoSt is submitted (not as each new sector commitment is added). // when a PoSt is submitted (not as each new sector commitment is added).
//
// AMT[sectorID]ffi.PublicSectorInfo
ProvingSet cid.Cid ProvingSet cid.Cid
// TODO: these: // TODO: these:

View File

@ -132,9 +132,8 @@ func NewGenerator() (*ChainGen, error) {
} }
minercfg := &GenMinerCfg{ minercfg := &GenMinerCfg{
Workers: []address.Address{worker1, worker2},
Owners: []address.Address{worker1, worker2},
PeerIDs: []peer.ID{"peerID1", "peerID2"}, PeerIDs: []peer.ID{"peerID1", "peerID2"},
// Call PreSeal(and give worker addrs to it somehow)
} }
genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{ genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{
@ -176,7 +175,7 @@ func NewGenerator() (*ChainGen, error) {
Miners: minercfg.MinerAddrs, Miners: minercfg.MinerAddrs,
eppProvs: mgen, eppProvs: mgen,
mworkers: minercfg.Workers, //mworkers: minercfg.Workers,
banker: banker, banker: banker,
receivers: receievers, receivers: receievers,

View File

@ -23,6 +23,14 @@ import (
"github.com/filecoin-project/lotus/genesis" "github.com/filecoin-project/lotus/genesis"
) )
var validSsizes = map[uint64]struct{}{}
func init() {
for _, size := range build.SectorSizes {
validSsizes[size] = struct{}{}
}
}
type GenesisBootstrap struct { type GenesisBootstrap struct {
Genesis *types.BlockHeader Genesis *types.BlockHeader
} }
@ -99,15 +107,6 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
return nil, xerrors.Errorf("set storage market actor: %w", err) return nil, xerrors.Errorf("set storage market actor: %w", err)
} }
smact, err := SetupStorageMarketActor(bs)
if err != nil {
return nil, xerrors.Errorf("setup storage market actor: %w", err)
}
if err := state.SetActor(actors.StorageMarketAddress, smact); err != nil {
return nil, xerrors.Errorf("set storage market actor: %w", err)
}
netAmt := types.FromFil(build.TotalFilecoin) netAmt := types.FromFil(build.TotalFilecoin)
for _, amt := range actmap { for _, amt := range actmap {
netAmt = types.BigSub(netAmt, amt) netAmt = types.BigSub(netAmt, amt)
@ -178,44 +177,60 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) {
}, nil }, nil
} }
func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { func SetupStorageMarketActor(bs bstore.Blockstore, sroot cid.Cid, deals []actors.StorageDeal) (cid.Cid, error) {
cst := hamt.CSTFromBstore(bs) cst := hamt.CSTFromBstore(bs)
nd := hamt.NewNode(cst) nd := hamt.NewNode(cst)
emptyHAMT, err := cst.Put(context.TODO(), nd) emptyHAMT, err := cst.Put(context.TODO(), nd)
if err != nil { if err != nil {
return nil, err return cid.Undef, err
} }
blks := amt.WrapBlockstore(bs) blks := amt.WrapBlockstore(bs)
emptyAMT, err := amt.FromArray(blks, nil) cdeals := make([]cbg.CBORMarshaler, len(deals))
for i, deal := range deals {
cdeals[i] = &actors.OnChainDeal{
Deal: deal,
ActivationEpoch: 1,
}
}
dealAmt, err := amt.FromArray(blks, cdeals)
if err != nil { if err != nil {
return nil, xerrors.Errorf("amt build failed: %w", err) return cid.Undef, xerrors.Errorf("amt build failed: %w", err)
} }
sms := &actors.StorageMarketState{ sms := &actors.StorageMarketState{
Balances: emptyHAMT, Balances: emptyHAMT,
Deals: emptyAMT, Deals: dealAmt,
NextDealID: 0, NextDealID: 0,
} }
stcid, err := cst.Put(context.TODO(), sms) stcid, err := cst.Put(context.TODO(), sms)
if err != nil { if err != nil {
return nil, err return cid.Undef, err
} }
return &types.Actor{ act := &types.Actor{
Code: actors.StorageMarketCodeCid, Code: actors.StorageMarketCodeCid,
Head: stcid, Head: stcid,
Nonce: 0, Nonce: 0,
Balance: types.NewInt(0), Balance: types.NewInt(0),
}, nil }
state, err := state.LoadStateTree(cst, sroot)
if err != nil {
return cid.Undef, xerrors.Errorf("making new state tree: %w", err)
}
if err := state.SetActor(actors.StorageMarketAddress, act); err != nil {
return cid.Undef, xerrors.Errorf("set storage market actor: %w", err)
}
return state.Flush()
} }
type GenMinerCfg struct { type GenMinerCfg struct {
Owners []address.Address
Workers []address.Address
PreSeals map[string]genesis.GenesisMiner PreSeals map[string]genesis.GenesisMiner
// The addresses of the created miner, this is set by the genesis setup // The addresses of the created miner, this is set by the genesis setup
@ -232,94 +247,100 @@ func mustEnc(i cbg.CBORMarshaler) []byte {
return enc return enc
} }
func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, error) { func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, []actors.StorageDeal, error) {
vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore()) vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore())
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) return cid.Undef, nil, xerrors.Errorf("failed to create NewVM: %w", err)
} }
for i := 0; i < len(gmcfg.Workers); i++ { if len(gmcfg.MinerAddrs) != len(gmcfg.PreSeals) {
owner := gmcfg.Owners[i] return cid.Undef, nil, xerrors.Errorf("miner address list, and preseal count doesn't match (%d != %d)", len(gmcfg.MinerAddrs), len(gmcfg.PreSeals))
worker := gmcfg.Workers[i] }
pid := gmcfg.PeerIDs[i]
params := mustEnc(&actors.CreateStorageMinerParams{ var deals []actors.StorageDeal
Owner: owner,
Worker: worker,
SectorSize: build.SectorSizes[0], // TODO: needs to come from preseals info
PeerID: pid,
})
// TODO: hardcoding 7000000 here is a little fragile, it changes any for i, maddr := range gmcfg.MinerAddrs {
ps, psok := gmcfg.PreSeals[maddr.String()]
if !psok {
return cid.Undef, nil, xerrors.Errorf("no preseal for miner %s", maddr)
}
minerParams := &actors.CreateStorageMinerParams{
Owner: ps.Owner,
Worker: ps.Worker,
SectorSize: ps.SectorSize,
PeerID: gmcfg.PeerIDs[i], // TODO: grab from preseal too
}
params := mustEnc(minerParams)
// TODO: hardcoding 6500 here is a little fragile, it changes any
// time anyone changes the initial account allocations // time anyone changes the initial account allocations
rval, err := doExecValue(ctx, vm, actors.StoragePowerAddress, owner, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params) rval, err := doExecValue(ctx, vm, actors.StoragePowerAddress, ps.Worker, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params)
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err) return cid.Undef, nil, xerrors.Errorf("failed to create genesis miner: %w", err)
} }
maddr, err := address.NewFromBytes(rval) maddr, err := address.NewFromBytes(rval)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
gmcfg.MinerAddrs = append(gmcfg.MinerAddrs, maddr) gmcfg.MinerAddrs = append(gmcfg.MinerAddrs, maddr)
params = mustEnc(&actors.UpdateStorageParams{Delta: types.NewInt(5000)}) power := types.BigMul(types.NewInt(minerParams.SectorSize), types.NewInt(uint64(len(ps.Sectors))))
params = mustEnc(&actors.UpdateStorageParams{Delta: power})
_, err = doExec(ctx, vm, actors.StoragePowerAddress, maddr, actors.SPAMethods.UpdateStorage, params) _, err = doExec(ctx, vm, actors.StoragePowerAddress, maddr, actors.SPAMethods.UpdateStorage, params)
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err) return cid.Undef, nil, xerrors.Errorf("failed to update total storage: %w", err)
} }
// UGLY HACKY MODIFICATION OF MINER POWER
// we have to flush the vm here because it buffers stuff internally for perf reasons // we have to flush the vm here because it buffers stuff internally for perf reasons
if _, err := vm.Flush(ctx); err != nil { if _, err := vm.Flush(ctx); err != nil {
return cid.Undef, xerrors.Errorf("vm.Flush failed: %w", err) return cid.Undef, nil, xerrors.Errorf("vm.Flush failed: %w", err)
} }
st := vm.StateTree() st := vm.StateTree()
mact, err := st.GetActor(maddr) mact, err := st.GetActor(maddr)
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("get miner actor failed: %w", err) return cid.Undef, nil, xerrors.Errorf("get miner actor failed: %w", err)
} }
cst := hamt.CSTFromBstore(cs.Blockstore()) cst := hamt.CSTFromBstore(cs.Blockstore())
var mstate actors.StorageMinerActorState var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mact.Head, &mstate); err != nil { if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return cid.Undef, xerrors.Errorf("getting miner actor state failed: %w", err) return cid.Undef, nil, xerrors.Errorf("getting miner actor state failed: %w", err)
} }
mstate.Power = types.NewInt(build.SectorSizes[0]) mstate.Power = types.NewInt(build.SectorSizes[0])
blks := amt.WrapBlockstore(cs.Blockstore()) blks := amt.WrapBlockstore(cs.Blockstore())
ps, ok := gmcfg.PreSeals[maddr.String()]
if ok {
for _, s := range ps.Sectors { for _, s := range ps.Sectors {
nssroot, err := actors.AddToSectorSet(ctx, blks, mstate.Sectors, s.SectorID, s.CommR[:], s.CommD[:]) nssroot, err := actors.AddToSectorSet(ctx, blks, mstate.Sectors, s.SectorID, s.CommR[:], s.CommD[:])
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("failed to add fake sector to sector set: %w", err) return cid.Undef, nil, xerrors.Errorf("failed to add fake sector to sector set: %w", err)
} }
mstate.Sectors = nssroot mstate.Sectors = nssroot
mstate.ProvingSet = nssroot mstate.ProvingSet = nssroot
}
} else { deals = append(deals, s.Deal)
log.Warning("No preseals for miner: ", maddr)
} }
nstate, err := cst.Put(ctx, &mstate) nstate, err := cst.Put(ctx, &mstate)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
mact.Head = nstate mact.Head = nstate
if err := st.SetActor(maddr, mact); err != nil { if err := st.SetActor(maddr, mact); err != nil {
return cid.Undef, err return cid.Undef, nil, err
} }
// End of super haxx
} }
return vm.Flush(ctx) c, err := vm.Flush(ctx)
return c, deals, err
} }
func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) { func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) {
@ -368,11 +389,16 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
// temp chainstore // temp chainstore
cs := store.NewChainStore(bs, datastore.NewMapDatastore()) cs := store.NewChainStore(bs, datastore.NewMapDatastore())
stateroot, err = SetupStorageMiners(ctx, cs, stateroot, gmcfg) stateroot, deals, err := SetupStorageMiners(ctx, cs, stateroot, gmcfg)
if err != nil { if err != nil {
return nil, xerrors.Errorf("setup storage miners failed: %w", err) return nil, xerrors.Errorf("setup storage miners failed: %w", err)
} }
stateroot, err = SetupStorageMarketActor(bs, stateroot, deals)
if err != nil {
return nil, xerrors.Errorf("setup storage market actor: %w", err)
}
blks := amt.WrapBlockstore(bs) blks := amt.WrapBlockstore(bs)
emptyroot, err := amt.FromArray(blks, nil) emptyroot, err := amt.FromArray(blks, nil)

View File

@ -41,6 +41,17 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) {
return w, nil return w, nil
} }
func KeyWallet(keys ...*Key) *Wallet {
m := make(map[address.Address]*Key)
for _, key := range keys {
m[key.Address] = key
}
return &Wallet{
keys: m,
}
}
func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*types.Signature, error) { func (w *Wallet) Sign(ctx context.Context, addr address.Address, msg []byte) (*types.Signature, error) {
ki, err := w.findKey(addr) ki, err := w.findKey(addr)
if err != nil { if err != nil {
@ -85,6 +96,11 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) {
if ok { if ok {
return k, nil return k, nil
} }
if w.keystore == nil {
log.Warn("findKey didn't find the key in in-memory wallet")
return nil, nil
}
ki, err := w.keystore.Get(KNamePrefix + addr.String()) ki, err := w.keystore.Get(KNamePrefix + addr.String())
if err != nil { if err != nil {
if xerrors.Is(err, types.ErrKeyInfoNotFound) { if xerrors.Is(err, types.ErrKeyInfoNotFound) {

View File

@ -1,6 +1,7 @@
package seed package seed
import ( import (
"context"
"crypto/sha256" "crypto/sha256"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -12,8 +13,12 @@ import (
badger "github.com/ipfs/go-ds-badger" badger "github.com/ipfs/go-ds-badger"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/genesis" "github.com/filecoin-project/lotus/genesis"
"github.com/filecoin-project/lotus/lib/sectorbuilder" "github.com/filecoin-project/lotus/lib/sectorbuilder"
) )
@ -52,7 +57,7 @@ func PreSeal(maddr address.Address, ssize uint64, sectors uint64, sbroot string,
r := rand.New(rand.NewSource(101)) r := rand.New(rand.NewSource(101))
size := sectorbuilder.UserBytesForSectorSize(ssize) size := sectorbuilder.UserBytesForSectorSize(ssize)
var sealedSectors []genesis.PreSeal var sealedSectors []*genesis.PreSeal
for i := uint64(1); i <= sectors; i++ { for i := uint64(1); i <= sectors; i++ {
sid, err := sb.AcquireSectorId() sid, err := sb.AcquireSectorId()
if err != nil { if err != nil {
@ -76,17 +81,35 @@ func PreSeal(maddr address.Address, ssize uint64, sectors uint64, sbroot string,
return xerrors.Errorf("commit: %w", err) return xerrors.Errorf("commit: %w", err)
} }
sealedSectors = append(sealedSectors, genesis.PreSeal{ sealedSectors = append(sealedSectors, &genesis.PreSeal{
CommR: pco.CommR, CommR: pco.CommR,
CommD: pco.CommD, CommD: pco.CommD,
SectorID: sid, SectorID: sid,
}) })
} }
output := map[string]genesis.GenesisMiner{ minerAddr, err := wallet.GenerateKey(types.KTBLS)
maddr.String(): genesis.GenesisMiner{ if err != nil {
return err
}
miner := &genesis.GenesisMiner{
Owner: minerAddr.Address,
Worker: minerAddr.Address,
SectorSize: ssize,
Sectors: sealedSectors, Sectors: sealedSectors,
},
Key: minerAddr.KeyInfo,
}
if err := createDeals(miner, minerAddr, ssize); err != nil {
return xerrors.Errorf("creating deals: %w", err)
}
output := map[string]genesis.GenesisMiner{
maddr.String(): *miner,
} }
out, err := json.MarshalIndent(output, "", " ") out, err := json.MarshalIndent(output, "", " ")
@ -104,3 +127,37 @@ func PreSeal(maddr address.Address, ssize uint64, sectors uint64, sbroot string,
return nil return nil
} }
func createDeals(m *genesis.GenesisMiner, k *wallet.Key, ssize uint64) error {
for _, sector := range m.Sectors {
proposal := &actors.StorageDealProposal{
PieceRef: sector.CommD[:], // just one deal so this == CommP
PieceSize: ssize,
PieceSerialization: actors.SerializationUnixFSv0,
Client: k.Address,
Provider: k.Address,
ProposalExpiration: 9000, // TODO: allow setting
Duration: 9000,
StoragePricePerEpoch: types.NewInt(0),
StorageCollateral: types.NewInt(0),
ProposerSignature: nil,
}
if err := api.SignWith(context.TODO(), wallet.KeyWallet(k).Sign, k.Address, proposal); err != nil {
return err
}
deal := &actors.StorageDeal{
Proposal: *proposal,
CounterSignature: nil,
}
if err := api.SignWith(context.TODO(), wallet.KeyWallet(k).Sign, k.Address, deal); err != nil {
return err
}
sector.Deal = *deal
}
return nil
}

View File

@ -1,15 +1,25 @@
package genesis package genesis
import "github.com/filecoin-project/lotus/chain/address" import (
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/address"
"github.com/filecoin-project/lotus/chain/types"
)
type PreSeal struct { type PreSeal struct {
CommR [32]byte CommR [32]byte
CommD [32]byte CommD [32]byte
SectorID uint64 SectorID uint64
Deal actors.StorageDeal
} }
type GenesisMiner struct { type GenesisMiner struct {
Sectors []PreSeal
Owner address.Address Owner address.Address
Worker address.Address Worker address.Address
SectorSize uint64
Sectors []*PreSeal
Key types.KeyInfo // TODO: separate file
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"golang.org/x/xerrors"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@ -39,9 +40,8 @@ func MakeGenesisMem(out io.Writer, minerPid peer.ID) func(bs dtypes.ChainBlockst
} }
gmc := &gen.GenMinerCfg{ gmc := &gen.GenMinerCfg{
Owners: []address.Address{w},
Workers: []address.Address{w},
PeerIDs: []peer.ID{minerPid}, PeerIDs: []peer.ID{minerPid},
// TODO: Call seal.PreSeal
} }
alloc := map[address.Address]types.BigInt{ alloc := map[address.Address]types.BigInt{
w: types.FromFil(10000), w: types.FromFil(10000),
@ -78,20 +78,34 @@ func MakeGenesis(outFile, preseal string) func(bs dtypes.ChainBlockstore, w *wal
return nil, err return nil, err
} }
minerAddr, err := w.GenerateKey(types.KTBLS) minerAddresses := make([]address.Address, 0, len(preseal))
for s := range preseal {
a, err := address.NewFromString(s)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if a.Protocol() != address.ID {
gmc := &gen.GenMinerCfg{ return nil, xerrors.New("expected ID address")
Owners: []address.Address{minerAddr}, }
Workers: []address.Address{minerAddr}, minerAddresses = append(minerAddresses, a)
PeerIDs: []peer.ID{"peer ID 1"},
PreSeals: preseal,
} }
addrs := map[address.Address]types.BigInt{ gmc := &gen.GenMinerCfg{
minerAddr: types.FromFil(100000), PeerIDs: []peer.ID{"peer ID 1"},
PreSeals: preseal,
MinerAddrs: minerAddresses,
}
addrs := map[address.Address]types.BigInt{}
for _, miner := range preseal {
if _, err := w.Import(&miner.Key); err != nil {
return nil, xerrors.Errorf("importing miner key: %w", err)
}
_ = w.SetDefault(miner.Worker)
addrs[miner.Worker] = types.FromFil(100000)
} }
b, err := gen.MakeGenesisBlock(bs, addrs, gmc, uint64(time.Now().Unix())) b, err := gen.MakeGenesisBlock(bs, addrs, gmc, uint64(time.Now().Unix()))