diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index 1de5ae2f1..1c574eb37 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -31,12 +31,16 @@ type StorageMinerActorState struct { PreCommittedSectors map[string]*PreCommittedSector // All sectors this miner has committed. + // + // AMT[sectorID]ffi.PublicSectorInfo Sectors cid.Cid // TODO: Spec says 'StagedCommittedSectors', which one is it? // Sectors this miner is currently mining. It is only updated // when a PoSt is submitted (not as each new sector commitment is added). + // + // AMT[sectorID]ffi.PublicSectorInfo ProvingSet cid.Cid // TODO: these: diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 9189f76c6..308439237 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -132,9 +132,8 @@ func NewGenerator() (*ChainGen, error) { } minercfg := &GenMinerCfg{ - Workers: []address.Address{worker1, worker2}, - Owners: []address.Address{worker1, worker2}, PeerIDs: []peer.ID{"peerID1", "peerID2"}, + // Call PreSeal(and give worker addrs to it somehow) } genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{ @@ -174,9 +173,9 @@ func NewGenerator() (*ChainGen, error) { genesis: genb.Genesis, w: w, - Miners: minercfg.MinerAddrs, - eppProvs: mgen, - mworkers: minercfg.Workers, + Miners: minercfg.MinerAddrs, + eppProvs: mgen, + //mworkers: minercfg.Workers, banker: banker, receivers: receievers, diff --git a/chain/gen/utils.go b/chain/gen/utils.go index aaf31c09a..82a9e907a 100644 --- a/chain/gen/utils.go +++ b/chain/gen/utils.go @@ -23,6 +23,14 @@ import ( "github.com/filecoin-project/lotus/genesis" ) +var validSsizes = map[uint64]struct{}{} + +func init() { + for _, size := range build.SectorSizes { + validSsizes[size] = struct{}{} + } +} + type GenesisBootstrap struct { 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) } - 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) for _, amt := range actmap { netAmt = types.BigSub(netAmt, amt) @@ -178,44 +177,60 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { }, 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) nd := hamt.NewNode(cst) emptyHAMT, err := cst.Put(context.TODO(), nd) if err != nil { - return nil, err + return cid.Undef, err } 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 { - return nil, xerrors.Errorf("amt build failed: %w", err) + return cid.Undef, xerrors.Errorf("amt build failed: %w", err) } sms := &actors.StorageMarketState{ Balances: emptyHAMT, - Deals: emptyAMT, + Deals: dealAmt, NextDealID: 0, } stcid, err := cst.Put(context.TODO(), sms) if err != nil { - return nil, err + return cid.Undef, err } - return &types.Actor{ + act := &types.Actor{ Code: actors.StorageMarketCodeCid, Head: stcid, Nonce: 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 { - Owners []address.Address - Workers []address.Address - PreSeals map[string]genesis.GenesisMiner // 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 } -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()) 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++ { - owner := gmcfg.Owners[i] - worker := gmcfg.Workers[i] - pid := gmcfg.PeerIDs[i] + if len(gmcfg.MinerAddrs) != len(gmcfg.PreSeals) { + return cid.Undef, nil, xerrors.Errorf("miner address list, and preseal count doesn't match (%d != %d)", len(gmcfg.MinerAddrs), len(gmcfg.PreSeals)) + } - params := mustEnc(&actors.CreateStorageMinerParams{ - Owner: owner, - Worker: worker, - SectorSize: build.SectorSizes[0], // TODO: needs to come from preseals info - PeerID: pid, - }) + var deals []actors.StorageDeal - // 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 - 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 { - 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) if err != nil { - return cid.Undef, err + return cid.Undef, nil, err } 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) 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 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() mact, err := st.GetActor(maddr) 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()) var mstate actors.StorageMinerActorState 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]) blks := amt.WrapBlockstore(cs.Blockstore()) - ps, ok := gmcfg.PreSeals[maddr.String()] - if ok { - for _, s := range ps.Sectors { - nssroot, err := actors.AddToSectorSet(ctx, blks, mstate.Sectors, s.SectorID, s.CommR[:], s.CommD[:]) - if err != nil { - return cid.Undef, xerrors.Errorf("failed to add fake sector to sector set: %w", err) - } - mstate.Sectors = nssroot - mstate.ProvingSet = nssroot + for _, s := range ps.Sectors { + nssroot, err := actors.AddToSectorSet(ctx, blks, mstate.Sectors, s.SectorID, s.CommR[:], s.CommD[:]) + if err != nil { + return cid.Undef, nil, xerrors.Errorf("failed to add fake sector to sector set: %w", err) } - } else { - log.Warning("No preseals for miner: ", maddr) + mstate.Sectors = nssroot + mstate.ProvingSet = nssroot + + deals = append(deals, s.Deal) } nstate, err := cst.Put(ctx, &mstate) if err != nil { - return cid.Undef, err + return cid.Undef, nil, err } mact.Head = nstate 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) { @@ -368,11 +389,16 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B // temp chainstore cs := store.NewChainStore(bs, datastore.NewMapDatastore()) - stateroot, err = SetupStorageMiners(ctx, cs, stateroot, gmcfg) + stateroot, deals, err := SetupStorageMiners(ctx, cs, stateroot, gmcfg) if err != nil { 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) emptyroot, err := amt.FromArray(blks, nil) diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index 9dec1864e..9ca4d2e0a 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -41,6 +41,17 @@ func NewWallet(keystore types.KeyStore) (*Wallet, error) { 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) { ki, err := w.findKey(addr) if err != nil { @@ -85,6 +96,11 @@ func (w *Wallet) findKey(addr address.Address) (*Key, error) { if ok { 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()) if err != nil { if xerrors.Is(err, types.ErrKeyInfoNotFound) { diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index 790897800..6e333371d 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -1,6 +1,7 @@ package seed import ( + "context" "crypto/sha256" "encoding/json" "fmt" @@ -12,8 +13,12 @@ import ( badger "github.com/ipfs/go-ds-badger" "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/api" "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/types" + "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/genesis" "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)) size := sectorbuilder.UserBytesForSectorSize(ssize) - var sealedSectors []genesis.PreSeal + var sealedSectors []*genesis.PreSeal for i := uint64(1); i <= sectors; i++ { sid, err := sb.AcquireSectorId() if err != nil { @@ -76,17 +81,35 @@ func PreSeal(maddr address.Address, ssize uint64, sectors uint64, sbroot string, return xerrors.Errorf("commit: %w", err) } - sealedSectors = append(sealedSectors, genesis.PreSeal{ + sealedSectors = append(sealedSectors, &genesis.PreSeal{ CommR: pco.CommR, CommD: pco.CommD, SectorID: sid, }) } + minerAddr, err := wallet.GenerateKey(types.KTBLS) + if err != nil { + return err + } + + miner := &genesis.GenesisMiner{ + Owner: minerAddr.Address, + Worker: minerAddr.Address, + + SectorSize: ssize, + + 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(): genesis.GenesisMiner{ - Sectors: sealedSectors, - }, + maddr.String(): *miner, } out, err := json.MarshalIndent(output, "", " ") @@ -104,3 +127,37 @@ func PreSeal(maddr address.Address, ssize uint64, sectors uint64, sbroot string, 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 +} diff --git a/genesis/types.go b/genesis/types.go index 36abd8f28..e8a208452 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -1,15 +1,25 @@ 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 { CommR [32]byte CommD [32]byte SectorID uint64 + Deal actors.StorageDeal } type GenesisMiner struct { - Sectors []PreSeal - Owner address.Address - Worker address.Address + Owner address.Address + Worker address.Address + + SectorSize uint64 + + Sectors []*PreSeal + + Key types.KeyInfo // TODO: separate file } diff --git a/node/modules/testing/genesis.go b/node/modules/testing/genesis.go index 5b6519e47..ee60af8b0 100644 --- a/node/modules/testing/genesis.go +++ b/node/modules/testing/genesis.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "golang.org/x/xerrors" "io" "io/ioutil" "os" @@ -39,9 +40,8 @@ func MakeGenesisMem(out io.Writer, minerPid peer.ID) func(bs dtypes.ChainBlockst } gmc := &gen.GenMinerCfg{ - Owners: []address.Address{w}, - Workers: []address.Address{w}, PeerIDs: []peer.ID{minerPid}, + // TODO: Call seal.PreSeal } alloc := map[address.Address]types.BigInt{ w: types.FromFil(10000), @@ -78,20 +78,34 @@ func MakeGenesis(outFile, preseal string) func(bs dtypes.ChainBlockstore, w *wal return nil, err } - minerAddr, err := w.GenerateKey(types.KTBLS) - if err != nil { - return nil, err + minerAddresses := make([]address.Address, 0, len(preseal)) + for s := range preseal { + a, err := address.NewFromString(s) + if err != nil { + return nil, err + } + if a.Protocol() != address.ID { + return nil, xerrors.New("expected ID address") + } + minerAddresses = append(minerAddresses, a) } gmc := &gen.GenMinerCfg{ - Owners: []address.Address{minerAddr}, - Workers: []address.Address{minerAddr}, - PeerIDs: []peer.ID{"peer ID 1"}, - PreSeals: preseal, + PeerIDs: []peer.ID{"peer ID 1"}, + PreSeals: preseal, + MinerAddrs: minerAddresses, } - addrs := map[address.Address]types.BigInt{ - minerAddr: types.FromFil(100000), + 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()))