From 63e801e00f0d7521cc6a88cf4340460ce2c11b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 11 Feb 2020 21:48:03 +0100 Subject: [PATCH] genesis: Cleanup the structure --- chain/actors/actors.go | 36 +- chain/actors/actors_test.go | 9 +- chain/actors/harness2_test.go | 7 +- chain/gen/gen.go | 10 +- chain/gen/genesis/genesis.go | 195 +++++++++ chain/gen/genesis/miners.go | 203 ++++++++++ chain/gen/genesis/t01_init.go | 164 ++++++++ chain/gen/genesis/t02_reward.go | 1 + chain/gen/genesis/t03_cron.go | 34 ++ chain/gen/genesis/t04_power.go | 95 +++++ chain/gen/genesis/t05_market.go | 80 ++++ chain/gen/genesis/util.go | 54 +++ chain/gen/utils.go | 691 -------------------------------- chain/stmgr/utils.go | 2 +- chain/sync.go | 2 +- chain/validation/state.go | 9 +- cmd/lotus-seed/seed/seed.go | 10 +- genesis/types.go | 8 +- node/modules/testing/genesis.go | 11 +- node/node_test.go | 8 +- storage/sealing/garbage.go | 5 +- 21 files changed, 882 insertions(+), 752 deletions(-) create mode 100644 chain/gen/genesis/genesis.go create mode 100644 chain/gen/genesis/miners.go create mode 100644 chain/gen/genesis/t01_init.go create mode 100644 chain/gen/genesis/t02_reward.go create mode 100644 chain/gen/genesis/t03_cron.go create mode 100644 chain/gen/genesis/t04_power.go create mode 100644 chain/gen/genesis/t05_market.go create mode 100644 chain/gen/genesis/util.go delete mode 100644 chain/gen/utils.go diff --git a/chain/actors/actors.go b/chain/actors/actors.go index 3203980f2..5311a8e41 100644 --- a/chain/actors/actors.go +++ b/chain/actors/actors.go @@ -2,19 +2,19 @@ package actors import ( "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/ipfs/go-cid" - mh "github.com/multiformats/go-multihash" ) -var AccountCodeCid cid.Cid -var CronCodeCid cid.Cid -var StoragePowerCodeCid cid.Cid -var StorageMarketCodeCid cid.Cid -var StorageMinerCodeCid cid.Cid -var MultisigCodeCid cid.Cid -var InitCodeCid cid.Cid -var PaymentChannelCodeCid cid.Cid +var AccountCodeCid = builtin.AccountActorCodeID +var CronCodeCid = builtin.CronActorCodeID +var StoragePowerCodeCid = builtin.StoragePowerActorCodeID +var StorageMarketCodeCid = builtin.StorageMarketActorCodeID +var StorageMinerCodeCid = builtin.StorageMinerActorCodeID +var MultisigCodeCid = builtin.MultisigActorCodeID +var InitCodeCid = builtin.InitActorCodeID +var PaymentChannelCodeCid = builtin.PaymentChannelActorCodeID var SystemAddress = mustIDAddress(0) var InitAddress = mustIDAddress(1) @@ -36,24 +36,6 @@ func mustIDAddress(i uint64) address.Address { } func init() { - pref := cid.NewPrefixV1(cid.Raw, mh.IDENTITY) - mustSum := func(s string) cid.Cid { - c, err := pref.Sum([]byte(s)) - if err != nil { - panic(err) // ok - } - return c - } - - AccountCodeCid = mustSum("fil/1/account") // TODO: spec - CronCodeCid = mustSum("fil/1/cron") - StoragePowerCodeCid = mustSum("fil/1/power") - StorageMarketCodeCid = mustSum("fil/1/market") - StorageMinerCodeCid = mustSum("fil/1/miner") - MultisigCodeCid = mustSum("fil/1/multisig") - InitCodeCid = mustSum("fil/1/init") - PaymentChannelCodeCid = mustSum("fil/1/paych") - BuiltInActors = map[cid.Cid]bool{ StorageMarketCodeCid: true, StoragePowerCodeCid: true, diff --git a/chain/actors/actors_test.go b/chain/actors/actors_test.go index 30f7b702e..6e832d0da 100644 --- a/chain/actors/actors_test.go +++ b/chain/actors/actors_test.go @@ -7,15 +7,16 @@ import ( "testing" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/go-address" + dstore "github.com/ipfs/go-datastore" + bstore "github.com/ipfs/go-ipfs-blockstore" + . "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - dstore "github.com/ipfs/go-datastore" - bstore "github.com/ipfs/go-ipfs-blockstore" ) func blsaddr(n uint64) address.Address { @@ -40,7 +41,7 @@ func setupVMTestEnv(t *testing.T) (*vm.VM, []address.Address, bstore.Blockstore) from: types.NewInt(1000000), maddr: types.NewInt(0), } - st, err := gen.MakeInitialStateTree(bs, actors) + st, err := genesis.MakeInitialStateTree(bs, actors) if err != nil { t.Fatal(err) } diff --git a/chain/actors/harness2_test.go b/chain/actors/harness2_test.go index 6378487c1..f9739f4a6 100644 --- a/chain/actors/harness2_test.go +++ b/chain/actors/harness2_test.go @@ -19,8 +19,9 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -183,7 +184,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness { } } - st, err := gen.MakeInitialStateTree(h.bs, h.HI.Addrs) + st, err := genesis.MakeInitialStateTree(h.bs, h.HI.Addrs) if err != nil { t.Fatal(err) } @@ -193,7 +194,7 @@ func NewHarness(t *testing.T, options ...HarnessOpt) *Harness { t.Fatal(err) } - stateroot, err = gen.SetupStorageMarketActor(h.bs, stateroot, nil) + stateroot, err = genesis.SetupStorageMarketActor(h.bs, stateroot, nil) if err != nil { t.Fatal(err) } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index e14cd0d9d..4bb2462ad 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -20,11 +20,13 @@ import ( "github.com/ipfs/go-merkledag" peer "github.com/libp2p/go-libp2p-core/peer" - ffi "github.com/filecoin-project/filecoin-ffi" "github.com/filecoin-project/go-address" sectorbuilder "github.com/filecoin-project/go-sectorbuilder" + + ffi "github.com/filecoin-project/filecoin-ffi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -165,7 +167,7 @@ func NewGenerator() (*ChainGen, error) { return nil, err } - minercfg := &GenMinerCfg{ + minercfg := &genesis2.GenMinerCfg{ PeerIDs: []peer.ID{"peerID1", "peerID2"}, PreSeals: map[string]genesis.GenesisMiner{ maddr1.String(): *genm1, @@ -176,7 +178,7 @@ func NewGenerator() (*ChainGen, error) { sys := vm.Syscalls(sectorbuilder.ProofVerifier) - genb, err := MakeGenesisBlock(bs, sys, map[address.Address]types.BigInt{ + genb, err := genesis2.MakeGenesisBlock(bs, sys, map[address.Address]types.BigInt{ mk1: types.FromFil(40000), mk2: types.FromFil(40000), banker: types.FromFil(50000), @@ -478,7 +480,7 @@ type eppProvider struct{} func (epp *eppProvider) GenerateCandidates(ctx context.Context, _ sectorbuilder.SortedPublicSectorInfo, eprand []byte) ([]sectorbuilder.EPostCandidate, error) { return []sectorbuilder.EPostCandidate{ { - SectorNum: 1, + SectorNum: 1, PartialTicket: [32]byte{}, Ticket: [32]byte{}, SectorChallengeIndex: 1, diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go new file mode 100644 index 000000000..64faec325 --- /dev/null +++ b/chain/gen/genesis/genesis.go @@ -0,0 +1,195 @@ +package genesis + +import ( + "context" + + "github.com/filecoin-project/go-amt-ipld/v2" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + bstore "github.com/ipfs/go-ipfs-blockstore" + cbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/build" + actors "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +var log = logging.Logger("genesis") + +type GenesisBootstrap struct { + Genesis *types.BlockHeader +} + +func MakeGenesisBlock(bs bstore.Blockstore, sys *types.VMSyscalls, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg, ts uint64) (*GenesisBootstrap, error) { + ctx := context.TODO() + + state, err := MakeInitialStateTree(bs, balances) + if err != nil { + return nil, xerrors.Errorf("make initial state tree failed: %w", err) + } + + stateroot, err := state.Flush(ctx) + if err != nil { + return nil, xerrors.Errorf("flush state tree failed: %w", err) + } + + // temp chainstore + cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys) + 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) + } + + stateroot, err = AdjustInitActorStartID(ctx, bs, stateroot, 1000) + if err != nil { + return nil, xerrors.Errorf("failed to adjust init actor start ID: %w", err) + } + + cst := cbor.NewCborStore(bs) + + emptyroot, err := amt.FromArray(ctx, cst, nil) + if err != nil { + return nil, xerrors.Errorf("amt build failed: %w", err) + } + + mm := &types.MsgMeta{ + BlsMessages: emptyroot, + SecpkMessages: emptyroot, + } + mmb, err := mm.ToStorageBlock() + if err != nil { + return nil, xerrors.Errorf("serializing msgmeta failed: %w", err) + } + if err := bs.Put(mmb); err != nil { + return nil, xerrors.Errorf("putting msgmeta block to blockstore: %w", err) + } + + log.Infof("Empty Genesis root: %s", emptyroot) + + genesisticket := &types.Ticket{ + VRFProof: []byte("vrf proof0000000vrf proof0000000"), + } + + b := &types.BlockHeader{ + Miner: actors.InitAddress, + Ticket: genesisticket, + EPostProof: types.EPostProof{ + Proof: []byte("not a real proof"), + PostRand: []byte("i guess this is kinda random"), + }, + Parents: []cid.Cid{}, + Height: 0, + ParentWeight: types.NewInt(0), + ParentStateRoot: stateroot, + Messages: mmb.Cid(), + ParentMessageReceipts: emptyroot, + BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")}, + BlockSig: &types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")}, + Timestamp: ts, + } + + sb, err := b.ToStorageBlock() + if err != nil { + return nil, xerrors.Errorf("serializing block header failed: %w", err) + } + + if err := bs.Put(sb); err != nil { + return nil, xerrors.Errorf("putting header to blockstore: %w", err) + } + + return &GenesisBootstrap{ + Genesis: b, + }, nil +} + +func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types.BigInt) (*state.StateTree, error) { + cst := cbor.NewCborStore(bs) + state, err := state.NewStateTree(cst) + if err != nil { + return nil, xerrors.Errorf("making new state tree: %w", err) + } + + emptyobject, err := cst.Put(context.TODO(), []struct{}{}) + if err != nil { + return nil, xerrors.Errorf("failed putting empty object: %w", err) + } + + var addrs []address.Address + for a := range actmap { + addrs = append(addrs, a) + } + + initact, err := SetupInitActor(bs, addrs) + if err != nil { + return nil, xerrors.Errorf("setup init actor: %w", err) + } + + if err := state.SetActor(actors.InitAddress, initact); err != nil { + return nil, xerrors.Errorf("set init actor: %w", err) + } + + cronact, err := SetupCronActor(bs) + if err != nil { + return nil, xerrors.Errorf("setup cron actor: %w", err) + } + + if err := state.SetActor(actors.CronAddress, cronact); err != nil { + return nil, xerrors.Errorf("set cron actor: %w", err) + } + + spact, err := SetupStoragePowerActor(bs) + if err != nil { + return nil, xerrors.Errorf("setup storage market actor: %w", err) + } + + if err := state.SetActor(actors.StoragePowerAddress, spact); 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) + } + + err = state.SetActor(actors.NetworkAddress, &types.Actor{ + Code: actors.AccountCodeCid, + Balance: netAmt, + Head: emptyobject, + }) + if err != nil { + return nil, xerrors.Errorf("set network account actor: %w", err) + } + + err = state.SetActor(actors.BurntFundsAddress, &types.Actor{ + Code: actors.AccountCodeCid, + Balance: types.NewInt(0), + Head: emptyobject, + }) + if err != nil { + return nil, xerrors.Errorf("set burnt funds account actor: %w", err) + } + + for a, v := range actmap { + err = state.SetActor(a, &types.Actor{ + Code: actors.AccountCodeCid, + Balance: v, + Head: emptyobject, + }) + if err != nil { + return nil, xerrors.Errorf("setting account from actmap: %w", err) + } + } + + return state, nil +} diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go new file mode 100644 index 000000000..527b6c1ff --- /dev/null +++ b/chain/gen/genesis/miners.go @@ -0,0 +1,203 @@ +package genesis + +import ( + "bytes" + "context" + + "github.com/filecoin-project/go-address" + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/libp2p/go-libp2p-core/peer" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/genesis" +) + +type GenMinerCfg struct { + PreSeals map[string]genesis.GenesisMiner + + // The addresses of the created miner, this is set by the genesis setup + MinerAddrs []address.Address + + PeerIDs []peer.ID +} + +func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, []actors.StorageDealProposal, error) { + vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore(), cs.VMSys()) + if err != nil { + return cid.Undef, nil, xerrors.Errorf("failed to create NewVM: %w", err) + } + + if len(gmcfg.MinerAddrs) == 0 { + return cid.Undef, nil, xerrors.New("no genesis miners") + } + + 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)) + } + + var deals []actors.StorageDealProposal + + 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 := &miner.ConstructorParams{ + OwnerAddr: ps.Owner, + WorkerAddr: 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, ps.Worker, types.FromFil(6500), actors.SPAMethods.CreateMiner, params) + if err != nil { + return cid.Undef, nil, xerrors.Errorf("failed to create genesis miner: %w", err) + } + + maddrret, err := address.NewFromBytes(rval) + if err != nil { + return cid.Undef, nil, err + } + + _, err = vm.Flush(ctx) + if err != nil { + return cid.Undef, nil, err + } + + cst := cbor.NewCborStore(cs.Blockstore()) + if err := reassignMinerActorAddress(vm, cst, maddrret, maddr); err != nil { + return cid.Undef, nil, err + } + + pledgeRequirements := make([]big.Int, len(ps.Sectors)) + for i, sector := range ps.Sectors { + if sector.Deal.StartEpoch != 0 { + return cid.Undef, nil, xerrors.New("all deals must start at epoch 0") + } + + dur := big.NewInt(int64(sector.Deal.Duration())) + siz := big.NewInt(int64(sector.Deal.PieceSize)) + weight := big.Mul(dur, siz) + + params = mustEnc(&power.OnSectorProveCommitParams{ + Weight: power.SectorStorageWeightDesc{ + SectorSize: ps.SectorSize, + Duration: sector.Deal.Duration(), + DealWeight: weight, + }}) + + ret, err := doExec(ctx, vm, actors.StoragePowerAddress, maddr, builtin.MethodsPower.OnSectorProveCommit, params) + if err != nil { + return cid.Undef, nil, xerrors.Errorf("failed to update total storage: %w", err) + } + if err := pledgeRequirements[i].UnmarshalCBOR(bytes.NewReader(ret)); err != nil { + return cid.Undef, nil, xerrors.Errorf("unmarshal pledge requirement: %w", err) + } + } + + // 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, nil, xerrors.Errorf("vm.Flush failed: %w", err) + } + + st := vm.StateTree() + mact, err := st.GetActor(maddr) + if err != nil { + return cid.Undef, nil, xerrors.Errorf("get miner actor failed: %w", err) + } + + var mstate miner.State + if err := cst.Get(ctx, mact.Head, &mstate); err != nil { + return cid.Undef, nil, xerrors.Errorf("getting miner actor state failed: %w", err) + } + + for i, s := range ps.Sectors { + dur := big.NewInt(int64(s.Deal.Duration())) + siz := big.NewInt(int64(s.Deal.PieceSize)) + weight := big.Mul(dur, siz) + + oci := miner.SectorOnChainInfo{ + Info: miner.SectorPreCommitInfo{ + SectorNumber: s.SectorID, + SealedCID: commcid.ReplicaCommitmentV1ToCID(s.CommR[:]), + SealEpoch: 0, + DealIDs: []abi.DealID{abi.DealID(len(deals))}, + Expiration: 0, + }, + ActivationEpoch: s.Deal.StartEpoch, + DealWeight: weight, + PledgeRequirement: pledgeRequirements[i], + DeclaredFaultEpoch: -1, + DeclaredFaultDuration: -1, + } + + nssroot := adt.AsArray(cs.Store(ctx), mstate.Sectors) + + if err := nssroot.Set(uint64(s.SectorID), &oci); err != nil { + return cid.Cid{}, nil, xerrors.Errorf("add sector to set: %w", err) + } + + mstate.Sectors = nssroot.Root() + mstate.ProvingSet = nssroot.Root() + + deals = append(deals, s.Deal) + } + + nstate, err := cst.Put(ctx, &mstate) + if err != nil { + return cid.Undef, nil, err + } + + mact.Head = nstate + if err := st.SetActor(maddr, mact); err != nil { + return cid.Undef, nil, err + } + } + + c, err := vm.Flush(ctx) + return c, deals, err +} + +func reassignMinerActorAddress(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { + if from == to { + return nil + } + act, err := vm.StateTree().GetActor(from) + if err != nil { + return xerrors.Errorf("reassign: failed to get 'from' actor: %w", err) + } + + _, err = vm.StateTree().GetActor(to) + if err == nil { + return xerrors.Errorf("cannot reassign actor, target address taken") + } + if err := vm.StateTree().SetActor(to, act); err != nil { + return xerrors.Errorf("failed to reassign actor: %w", err) + } + + // TODO: remove from + + if err := adjustStoragePowerTracking(vm, cst, from, to); err != nil { + return xerrors.Errorf("adjusting storage market tracking: %w", err) + } + + // Now, adjust the tracking in the init actor + return initActorReassign(vm, cst, from, to) +} diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go new file mode 100644 index 000000000..26a52a0b2 --- /dev/null +++ b/chain/gen/genesis/t01_init.go @@ -0,0 +1,164 @@ +package genesis + +import ( + "bytes" + "context" + + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-hamt-ipld" + blockstore "github.com/ipfs/go-ipfs-blockstore" + bstore "github.com/ipfs/go-ipfs-blockstore" + cbor "github.com/ipfs/go-ipld-cbor" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" +) + +func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor, error) { + var ias actors.InitActorState + ias.NextID = 100 + + cst := cbor.NewCborStore(bs) + amap := hamt.NewNode(cst) + + for i, a := range addrs { + if err := amap.Set(context.TODO(), string(a.Bytes()), 100+uint64(i)); err != nil { + return nil, err + } + } + + ias.NextID += uint64(len(addrs)) + if err := amap.Flush(context.TODO()); err != nil { + return nil, err + } + amapcid, err := cst.Put(context.TODO(), amap) + if err != nil { + return nil, err + } + + ias.AddressMap = amapcid + + statecid, err := cst.Put(context.TODO(), &ias) + if err != nil { + return nil, err + } + + act := &types.Actor{ + Code: actors.InitCodeCid, + Head: statecid, + } + + return act, nil +} + +func AdjustInitActorStartID(ctx context.Context, bs blockstore.Blockstore, stateroot cid.Cid, val uint64) (cid.Cid, error) { + cst := cbor.NewCborStore(bs) + + tree, err := state.LoadStateTree(cst, stateroot) + if err != nil { + return cid.Undef, err + } + + act, err := tree.GetActor(actors.InitAddress) + if err != nil { + return cid.Undef, err + } + + var st actors.InitActorState + if err := cst.Get(ctx, act.Head, &st); err != nil { + return cid.Undef, err + } + + st.NextID = val + + nstate, err := cst.Put(ctx, &st) + if err != nil { + return cid.Undef, err + } + + act.Head = nstate + + if err := tree.SetActor(actors.InitAddress, act); err != nil { + return cid.Undef, err + } + + return tree.Flush(ctx) +} + +func initActorReassign(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { + ctx := context.TODO() + initact, err := vm.StateTree().GetActor(actors.InitAddress) + if err != nil { + return xerrors.Errorf("couldnt get init actor: %w", err) + } + + var st actors.InitActorState + if err := cst.Get(ctx, initact.Head, &st); err != nil { + return xerrors.Errorf("reassign loading init actor state: %w", err) + } + + amap, err := hamt.LoadNode(ctx, cst, st.AddressMap) + if err != nil { + return xerrors.Errorf("failed to load init actor map: %w", err) + } + + target, err := address.IDFromAddress(from) + if err != nil { + return xerrors.Errorf("failed to extract ID: %w", err) + } + + var out string + halt := xerrors.Errorf("halt") + err = amap.ForEach(ctx, func(k string, v interface{}) error { + _, val, err := cbg.CborReadHeader(bytes.NewReader(v.(*cbg.Deferred).Raw)) + if err != nil { + return xerrors.Errorf("parsing int in map failed: %w", err) + } + + if val == target { + out = k + return halt + } + return nil + }) + + if err == nil { + return xerrors.Errorf("could not find from address in init ID map") + } + if !xerrors.Is(err, halt) { + return xerrors.Errorf("finding address in ID map failed: %w", err) + } + + if err := amap.Delete(ctx, out); err != nil { + return xerrors.Errorf("deleting 'from' entry in amap: %w", err) + } + + if err := amap.Set(ctx, out, target); err != nil { + return xerrors.Errorf("setting 'to' entry in amap: %w", err) + } + + if err := amap.Flush(ctx); err != nil { + return xerrors.Errorf("failed to flush amap: %w", err) + } + + ncid, err := cst.Put(ctx, amap) + if err != nil { + return err + } + + st.AddressMap = ncid + + nacthead, err := cst.Put(ctx, &st) + if err != nil { + return err + } + + initact.Head = nacthead + + return nil +} diff --git a/chain/gen/genesis/t02_reward.go b/chain/gen/genesis/t02_reward.go new file mode 100644 index 000000000..d215223ac --- /dev/null +++ b/chain/gen/genesis/t02_reward.go @@ -0,0 +1 @@ +package genesis diff --git a/chain/gen/genesis/t03_cron.go b/chain/gen/genesis/t03_cron.go new file mode 100644 index 000000000..bc2a8cde3 --- /dev/null +++ b/chain/gen/genesis/t03_cron.go @@ -0,0 +1,34 @@ +package genesis + +import ( + "context" + + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/cron" + bstore "github.com/ipfs/go-ipfs-blockstore" + cbor "github.com/ipfs/go-ipld-cbor" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" +) + +func SetupCronActor(bs bstore.Blockstore) (*types.Actor, error) { + cst := cbor.NewCborStore(bs) + cas := &actors.CronActorState{Entries: []cron.Entry{{ + Receiver: builtin.StoragePowerActorAddr, + MethodNum: builtin.MethodsPower.OnEpochTickEnd, + }, + }} + + stcid, err := cst.Put(context.TODO(), cas) + if err != nil { + return nil, err + } + + return &types.Actor{ + Code: actors.CronCodeCid, + Head: stcid, + Nonce: 0, + Balance: types.NewInt(0), + }, nil +} diff --git a/chain/gen/genesis/t04_power.go b/chain/gen/genesis/t04_power.go new file mode 100644 index 000000000..ed49ec2a8 --- /dev/null +++ b/chain/gen/genesis/t04_power.go @@ -0,0 +1,95 @@ +package genesis + +import ( + "context" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/ipfs/go-hamt-ipld" + bstore "github.com/ipfs/go-ipfs-blockstore" + cbor "github.com/ipfs/go-ipld-cbor" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" +) + +func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { + ctx := context.TODO() + cst := cbor.NewCborStore(bs) + nd := hamt.NewNode(cst) + emptyhamt, err := cst.Put(ctx, nd) + if err != nil { + return nil, err + } + + sms := &power.State{ + TotalNetworkPower: big.Zero(), + MinerCount: 0, + EscrowTable: emptyhamt, + CronEventQueue: emptyhamt, + PoStDetectedFaultMiners: emptyhamt, + Claims: emptyhamt, + NumMinersMeetingMinPower: 0, + } + + stcid, err := cst.Put(ctx, sms) + if err != nil { + return nil, err + } + + return &types.Actor{ + Code: actors.StoragePowerCodeCid, + Head: stcid, + Nonce: 0, + Balance: types.NewInt(0), + }, nil +} + +func adjustStoragePowerTracking(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { + ctx := context.TODO() + act, err := vm.StateTree().GetActor(actors.StoragePowerAddress) + if err != nil { + return xerrors.Errorf("loading storage power actor: %w", err) + } + + var spst market.State + if err := cst.Get(ctx, act.Head, &spst); err != nil { + return xerrors.Errorf("loading storage power actor state: %w", err) + } + + miners, err := hamt.LoadNode(ctx, cst, spst.Miners) + if err != nil { + return xerrors.Errorf("loading miner set: %w", err) + } + + if err := miners.Delete(ctx, string(from.Bytes())); err != nil { + return xerrors.Errorf("deleting from spa set: %w", err) + } + + if err := miners.Set(ctx, string(to.Bytes()), uint64(1)); err != nil { + return xerrors.Errorf("failed setting miner: %w", err) + } + + if err := miners.Flush(ctx); err != nil { + return err + } + + nminerscid, err := cst.Put(ctx, miners) + if err != nil { + return err + } + spst.Miners = nminerscid + + nhead, err := cst.Put(ctx, &spst) + if err != nil { + return err + } + + act.Head = nhead + + return nil +} diff --git a/chain/gen/genesis/t05_market.go b/chain/gen/genesis/t05_market.go new file mode 100644 index 000000000..56c7e7327 --- /dev/null +++ b/chain/gen/genesis/t05_market.go @@ -0,0 +1,80 @@ +package genesis + +import ( + "context" + + "github.com/filecoin-project/go-amt-ipld/v2" + "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/ipfs/go-cid" + bstore "github.com/ipfs/go-ipfs-blockstore" + cbor "github.com/ipfs/go-ipld-cbor" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +func SetupStorageMarketActor(bs bstore.Blockstore, sroot cid.Cid, deals []market.DealProposal) (cid.Cid, error) { + ctx := context.TODO() + cst := cbor.NewCborStore(bs) + ast := store.ActorStore(context.TODO(), bs) + + cdeals := make([]cbg.CBORMarshaler, len(deals)) + sdeals := make([]cbg.CBORMarshaler, len(deals)) + for i, deal := range deals { + d := deal // copy + + cdeals[i] = &d + sdeals[i] = &market.DealState{ + SectorStartEpoch: 1, + LastUpdatedEpoch: -1, + SlashEpoch: -1, + } + } + + dealAmt, err := amt.FromArray(ctx, cst, cdeals) + if err != nil { + return cid.Undef, xerrors.Errorf("amt build failed: %w", err) + } + + stateAmt, err := amt.FromArray(ctx, cst, sdeals) + if err != nil { + return cid.Undef, xerrors.Errorf("amt build failed: %w", err) + } + + sms, err := market.ConstructState(ast) + if err != nil { + return cid.Cid{}, err + } + + sms.Proposals = dealAmt + sms.States = stateAmt + + stcid, err := cst.Put(context.TODO(), sms) + if err != nil { + return cid.Undef, err + } + + // TODO: MARKET BALANCES!!!!!!111 + + act := &types.Actor{ + Code: actors.StorageMarketCodeCid, + Head: stcid, + Nonce: 0, + Balance: types.NewInt(0), + } + + 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(context.TODO()) +} diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go new file mode 100644 index 000000000..47ba01718 --- /dev/null +++ b/chain/gen/genesis/util.go @@ -0,0 +1,54 @@ +package genesis + +import ( + "context" + "fmt" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" +) + +func mustEnc(i cbg.CBORMarshaler) []byte { + enc, err := actors.SerializeParams(i) + if err != nil { + panic(err) // ok + } + return enc +} + +func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method abi.MethodNum, params []byte) ([]byte, error) { + return doExecValue(ctx, vm, to, from, types.NewInt(0), method, params) +} + +func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { + act, err := vm.StateTree().GetActor(from) + if err != nil { + return nil, xerrors.Errorf("doExec failed to get from actor: %w", err) + } + + ret, err := vm.ApplyMessage(context.TODO(), &types.Message{ + To: to, + From: from, + Method: method, + Params: params, + GasLimit: types.NewInt(1000000), + GasPrice: types.NewInt(0), + Value: value, + Nonce: act.Nonce, + }) + if err != nil { + return nil, xerrors.Errorf("doExec apply message failed: %w", err) + } + + if ret.ExitCode != 0 { + return nil, fmt.Errorf("failed to call method: %s", ret.ActorErr) + } + + return ret.Return, nil +} diff --git a/chain/gen/utils.go b/chain/gen/utils.go deleted file mode 100644 index 43018fcf1..000000000 --- a/chain/gen/utils.go +++ /dev/null @@ -1,691 +0,0 @@ -package gen - -import ( - "bytes" - "context" - "fmt" - - amt "github.com/filecoin-project/go-amt-ipld/v2" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" - hamt "github.com/ipfs/go-hamt-ipld" - blockstore "github.com/ipfs/go-ipfs-blockstore" - bstore "github.com/ipfs/go-ipfs-blockstore" - cbor "github.com/ipfs/go-ipld-cbor" - peer "github.com/libp2p/go-libp2p-core/peer" - cbg "github.com/whyrusleeping/cbor-gen" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-address" - - "github.com/filecoin-project/lotus/build" - actors "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/lotus/genesis" -) - -type GenesisBootstrap struct { - Genesis *types.BlockHeader -} - -func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor, error) { - var ias actors.InitActorState - ias.NextID = 100 - - cst := cbor.NewCborStore(bs) - amap := hamt.NewNode(cst) - - for i, a := range addrs { - if err := amap.Set(context.TODO(), string(a.Bytes()), 100+uint64(i)); err != nil { - return nil, err - } - } - - ias.NextID += uint64(len(addrs)) - if err := amap.Flush(context.TODO()); err != nil { - return nil, err - } - amapcid, err := cst.Put(context.TODO(), amap) - if err != nil { - return nil, err - } - - ias.AddressMap = amapcid - - statecid, err := cst.Put(context.TODO(), &ias) - if err != nil { - return nil, err - } - - act := &types.Actor{ - Code: actors.InitCodeCid, - Head: statecid, - } - - return act, nil -} - -func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types.BigInt) (*state.StateTree, error) { - cst := cbor.NewCborStore(bs) - state, err := state.NewStateTree(cst) - if err != nil { - return nil, xerrors.Errorf("making new state tree: %w", err) - } - - emptyobject, err := cst.Put(context.TODO(), map[string]string{}) - if err != nil { - return nil, xerrors.Errorf("failed putting empty object: %w", err) - } - - var addrs []address.Address - for a := range actmap { - addrs = append(addrs, a) - } - - initact, err := SetupInitActor(bs, addrs) - if err != nil { - return nil, xerrors.Errorf("setup init actor: %w", err) - } - - if err := state.SetActor(actors.InitAddress, initact); err != nil { - return nil, xerrors.Errorf("set init actor: %w", err) - } - - cronact, err := SetupCronActor(bs) - if err != nil { - return nil, xerrors.Errorf("setup cron actor: %w", err) - } - - if err := state.SetActor(actors.CronAddress, cronact); err != nil { - return nil, xerrors.Errorf("set cron actor: %w", err) - } - - spact, err := SetupStoragePowerActor(bs) - if err != nil { - return nil, xerrors.Errorf("setup storage market actor: %w", err) - } - - if err := state.SetActor(actors.StoragePowerAddress, spact); 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) - } - - err = state.SetActor(actors.NetworkAddress, &types.Actor{ - Code: actors.AccountCodeCid, - Balance: netAmt, - Head: emptyobject, - }) - if err != nil { - return nil, xerrors.Errorf("set network account actor: %w", err) - } - - err = state.SetActor(actors.BurntFundsAddress, &types.Actor{ - Code: actors.AccountCodeCid, - Balance: types.NewInt(0), - Head: emptyobject, - }) - if err != nil { - return nil, xerrors.Errorf("set burnt funds account actor: %w", err) - } - - for a, v := range actmap { - err = state.SetActor(a, &types.Actor{ - Code: actors.AccountCodeCid, - Balance: v, - Head: emptyobject, - }) - if err != nil { - return nil, xerrors.Errorf("setting account from actmap: %w", err) - } - } - - return state, nil -} - -func SetupCronActor(bs bstore.Blockstore) (*types.Actor, error) { - cst := cbor.NewCborStore(bs) - cas := &actors.CronActorState{} - - stcid, err := cst.Put(context.TODO(), cas) - if err != nil { - return nil, err - } - - return &types.Actor{ - Code: actors.CronCodeCid, - Head: stcid, - Nonce: 0, - Balance: types.NewInt(0), - }, nil -} - -func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { - ctx := context.TODO() - cst := cbor.NewCborStore(bs) - nd := hamt.NewNode(cst) - emptyhamt, err := cst.Put(ctx, nd) - if err != nil { - return nil, err - } - - sms := &power.State{ - TotalNetworkPower: big.Zero(), - MinerCount: 0, - EscrowTable: emptyhamt, - CronEventQueue: emptyhamt, - PoStDetectedFaultMiners: emptyhamt, - Claims: emptyhamt, - NumMinersMeetingMinPower: 0, - } - - stcid, err := cst.Put(ctx, sms) - if err != nil { - return nil, err - } - - return &types.Actor{ - Code: actors.StoragePowerCodeCid, - Head: stcid, - Nonce: 0, - Balance: types.NewInt(0), - }, nil -} - -func SetupStorageMarketActor(bs bstore.Blockstore, sroot cid.Cid, deals []actors.StorageDealProposal) (cid.Cid, error) { - ctx := context.TODO() - cst := cbor.NewCborStore(bs) - ast := store.ActorStore(context.TODO(), bs) - - cdeals := make([]cbg.CBORMarshaler, len(deals)) - sdeals := make([]cbg.CBORMarshaler, len(deals)) - for i, deal := range deals { - cdeals[i] = &market.DealProposal{ - PieceCID: deal.PieceCID, - PieceSize: deal.PieceSize, - Client: deal.Client, - Provider: deal.Provider, - StartEpoch: deal.StartEpoch, - EndEpoch: deal.EndEpoch, - StoragePricePerEpoch: deal.StoragePricePerEpoch, - ProviderCollateral: deal.ProviderCollateral, - ClientCollateral: deal.ClientCollateral, - } - sdeals[i] = &market.DealState{ - SectorStartEpoch: 1, - LastUpdatedEpoch: -1, - SlashEpoch: -1, - } - } - - dealAmt, err := amt.FromArray(ctx, cst, cdeals) - if err != nil { - return cid.Undef, xerrors.Errorf("amt build failed: %w", err) - } - - stateAmt, err := amt.FromArray(ctx, cst, sdeals) - if err != nil { - return cid.Undef, xerrors.Errorf("amt build failed: %w", err) - } - - sms, err := market.ConstructState(ast) - if err != nil { - return cid.Cid{}, err - } - - sms.Proposals = dealAmt - sms.States = stateAmt - - stcid, err := cst.Put(context.TODO(), sms) - if err != nil { - return cid.Undef, err - } - - // TODO: MARKET BALANCES!!!!!!111 - - act := &types.Actor{ - Code: actors.StorageMarketCodeCid, - Head: stcid, - Nonce: 0, - Balance: types.NewInt(0), - } - - 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(context.TODO()) -} - -type GenMinerCfg struct { - PreSeals map[string]genesis.GenesisMiner - - // The addresses of the created miner, this is set by the genesis setup - MinerAddrs []address.Address - - PeerIDs []peer.ID -} - -func mustEnc(i cbg.CBORMarshaler) []byte { - enc, err := actors.SerializeParams(i) - if err != nil { - panic(err) // ok - } - return enc -} - -func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, gmcfg *GenMinerCfg) (cid.Cid, []actors.StorageDealProposal, error) { - vm, err := vm.NewVM(sroot, 0, nil, actors.NetworkAddress, cs.Blockstore(), cs.VMSys()) - if err != nil { - return cid.Undef, nil, xerrors.Errorf("failed to create NewVM: %w", err) - } - - if len(gmcfg.MinerAddrs) == 0 { - return cid.Undef, nil, xerrors.New("no genesis miners") - } - - 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)) - } - - var deals []actors.StorageDealProposal - - 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 := &miner.ConstructorParams{ - OwnerAddr: ps.Owner, - WorkerAddr: 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, ps.Worker, types.FromFil(6500), actors.SPAMethods.CreateMiner, params) - if err != nil { - return cid.Undef, nil, xerrors.Errorf("failed to create genesis miner: %w", err) - } - - maddrret, err := address.NewFromBytes(rval) - if err != nil { - return cid.Undef, nil, err - } - - _, err = vm.Flush(ctx) - if err != nil { - return cid.Undef, nil, err - } - - cst := cbor.NewCborStore(cs.Blockstore()) - if err := reassignMinerActorAddress(vm, cst, maddrret, maddr); err != nil { - return cid.Undef, nil, err - } - - power := types.BigMul(types.NewInt(uint64(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, nil, xerrors.Errorf("failed to update total storage: %w", err) - } - - // 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, nil, xerrors.Errorf("vm.Flush failed: %w", err) - } - - st := vm.StateTree() - mact, err := st.GetActor(maddr) - if err != nil { - return cid.Undef, nil, xerrors.Errorf("get miner actor failed: %w", err) - } - - var mstate actors.StorageMinerActorState - if err := cst.Get(ctx, mact.Head, &mstate); err != nil { - return cid.Undef, nil, xerrors.Errorf("getting miner actor state failed: %w", err) - } - mstate.Power = types.BigMul(types.NewInt(uint64(ps.SectorSize)), types.NewInt(uint64(len(ps.Sectors)))) - - for _, s := range ps.Sectors { - nssroot, err := actors.AddToSectorSet(ctx, cst, 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) - } - mstate.Sectors = nssroot - mstate.ProvingSet = nssroot - - deals = append(deals, s.Deal) - } - - nstate, err := cst.Put(ctx, &mstate) - if err != nil { - return cid.Undef, nil, err - } - - mact.Head = nstate - if err := st.SetActor(maddr, mact); err != nil { - return cid.Undef, nil, err - } - } - - c, err := vm.Flush(ctx) - return c, deals, err -} - -func reassignMinerActorAddress(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { - if from == to { - return nil - } - act, err := vm.StateTree().GetActor(from) - if err != nil { - return xerrors.Errorf("reassign: failed to get 'from' actor: %w", err) - } - - _, err = vm.StateTree().GetActor(to) - if err == nil { - return xerrors.Errorf("cannot reassign actor, target address taken") - } - if err := vm.StateTree().SetActor(to, act); err != nil { - return xerrors.Errorf("failed to reassign actor: %w", err) - } - - if err := adjustStorageMarketTracking(vm, cst, from, to); err != nil { - return xerrors.Errorf("adjusting storage market tracking: %w", err) - } - - // Now, adjust the tracking in the init actor - return initActorReassign(vm, cst, from, to) -} - -func adjustStorageMarketTracking(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { - ctx := context.TODO() - act, err := vm.StateTree().GetActor(actors.StoragePowerAddress) - if err != nil { - return xerrors.Errorf("loading storage power actor: %w", err) - } - - var spst actors.StoragePowerState - if err := cst.Get(ctx, act.Head, &spst); err != nil { - return xerrors.Errorf("loading storage power actor state: %w", err) - } - - miners, err := hamt.LoadNode(ctx, cst, spst.Miners) - if err != nil { - return xerrors.Errorf("loading miner set: %w", err) - } - - if err := miners.Delete(ctx, string(from.Bytes())); err != nil { - return xerrors.Errorf("deleting from spa set: %w", err) - } - - if err := miners.Set(ctx, string(to.Bytes()), uint64(1)); err != nil { - return xerrors.Errorf("failed setting miner: %w", err) - } - - if err := miners.Flush(ctx); err != nil { - return err - } - - nminerscid, err := cst.Put(ctx, miners) - if err != nil { - return err - } - spst.Miners = nminerscid - - nhead, err := cst.Put(ctx, &spst) - if err != nil { - return err - } - - act.Head = nhead - - return nil -} - -func initActorReassign(vm *vm.VM, cst cbor.IpldStore, from, to address.Address) error { - ctx := context.TODO() - initact, err := vm.StateTree().GetActor(actors.InitAddress) - if err != nil { - return xerrors.Errorf("couldnt get init actor: %w", err) - } - - var st actors.InitActorState - if err := cst.Get(ctx, initact.Head, &st); err != nil { - return xerrors.Errorf("reassign loading init actor state: %w", err) - } - - amap, err := hamt.LoadNode(ctx, cst, st.AddressMap) - if err != nil { - return xerrors.Errorf("failed to load init actor map: %w", err) - } - - target, err := address.IDFromAddress(from) - if err != nil { - return xerrors.Errorf("failed to extract ID: %w", err) - } - - var out string - halt := xerrors.Errorf("halt") - err = amap.ForEach(ctx, func(k string, v interface{}) error { - _, val, err := cbg.CborReadHeader(bytes.NewReader(v.(*cbg.Deferred).Raw)) - if err != nil { - return xerrors.Errorf("parsing int in map failed: %w", err) - } - - if val == target { - out = k - return halt - } - return nil - }) - - if err == nil { - return xerrors.Errorf("could not find from address in init ID map") - } - if !xerrors.Is(err, halt) { - return xerrors.Errorf("finding address in ID map failed: %w", err) - } - - if err := amap.Delete(ctx, out); err != nil { - return xerrors.Errorf("deleting 'from' entry in amap: %w", err) - } - - if err := amap.Set(ctx, out, target); err != nil { - return xerrors.Errorf("setting 'to' entry in amap: %w", err) - } - - if err := amap.Flush(ctx); err != nil { - return xerrors.Errorf("failed to flush amap: %w", err) - } - - ncid, err := cst.Put(ctx, amap) - if err != nil { - return err - } - - st.AddressMap = ncid - - nacthead, err := cst.Put(ctx, &st) - if err != nil { - return err - } - - initact.Head = nacthead - - return nil -} - -func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) { - return doExecValue(ctx, vm, to, from, types.NewInt(0), method, params) -} - -func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value types.BigInt, method abi.MethodNum, params []byte) ([]byte, error) { - act, err := vm.StateTree().GetActor(from) - if err != nil { - return nil, xerrors.Errorf("doExec failed to get from actor: %w", err) - } - - ret, err := vm.ApplyMessage(context.TODO(), &types.Message{ - To: to, - From: from, - Method: method, - Params: params, - GasLimit: types.NewInt(1000000), - GasPrice: types.NewInt(0), - Value: value, - Nonce: act.Nonce, - }) - if err != nil { - return nil, xerrors.Errorf("doExec apply message failed: %w", err) - } - - if ret.ExitCode != 0 { - return nil, fmt.Errorf("failed to call method: %s", ret.ActorErr) - } - - return ret.Return, nil -} - -func MakeGenesisBlock(bs bstore.Blockstore, sys *types.VMSyscalls, balances map[address.Address]types.BigInt, gmcfg *GenMinerCfg, ts uint64) (*GenesisBootstrap, error) { - ctx := context.TODO() - - state, err := MakeInitialStateTree(bs, balances) - if err != nil { - return nil, xerrors.Errorf("make initial state tree failed: %w", err) - } - - stateroot, err := state.Flush(ctx) - if err != nil { - return nil, xerrors.Errorf("flush state tree failed: %w", err) - } - - // temp chainstore - cs := store.NewChainStore(bs, datastore.NewMapDatastore(), sys) - 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) - } - - stateroot, err = AdjustInitActorStartID(ctx, bs, stateroot, 1000) - if err != nil { - return nil, xerrors.Errorf("failed to adjust init actor start ID: %w", err) - } - - cst := cbor.NewCborStore(bs) - - emptyroot, err := amt.FromArray(ctx, cst, nil) - if err != nil { - return nil, xerrors.Errorf("amt build failed: %w", err) - } - - mm := &types.MsgMeta{ - BlsMessages: emptyroot, - SecpkMessages: emptyroot, - } - mmb, err := mm.ToStorageBlock() - if err != nil { - return nil, xerrors.Errorf("serializing msgmeta failed: %w", err) - } - if err := bs.Put(mmb); err != nil { - return nil, xerrors.Errorf("putting msgmeta block to blockstore: %w", err) - } - - log.Infof("Empty Genesis root: %s", emptyroot) - - genesisticket := &types.Ticket{ - VRFProof: []byte("vrf proof0000000vrf proof0000000"), - } - - b := &types.BlockHeader{ - Miner: actors.InitAddress, - Ticket: genesisticket, - EPostProof: types.EPostProof{ - Proof: []byte("not a real proof"), - PostRand: []byte("i guess this is kinda random"), - }, - Parents: []cid.Cid{}, - Height: 0, - ParentWeight: types.NewInt(0), - ParentStateRoot: stateroot, - Messages: mmb.Cid(), - ParentMessageReceipts: emptyroot, - BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")}, - BlockSig: &types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")}, - Timestamp: ts, - } - - sb, err := b.ToStorageBlock() - if err != nil { - return nil, xerrors.Errorf("serializing block header failed: %w", err) - } - - if err := bs.Put(sb); err != nil { - return nil, xerrors.Errorf("putting header to blockstore: %w", err) - } - - return &GenesisBootstrap{ - Genesis: b, - }, nil -} - -func AdjustInitActorStartID(ctx context.Context, bs blockstore.Blockstore, stateroot cid.Cid, val uint64) (cid.Cid, error) { - cst := cbor.NewCborStore(bs) - - tree, err := state.LoadStateTree(cst, stateroot) - if err != nil { - return cid.Undef, err - } - - act, err := tree.GetActor(actors.InitAddress) - if err != nil { - return cid.Undef, err - } - - var st actors.InitActorState - if err := cst.Get(ctx, act.Head, &st); err != nil { - return cid.Undef, err - } - - st.NextID = val - - nstate, err := cst.Put(ctx, &st) - if err != nil { - return cid.Undef, err - } - - act.Head = nstate - - if err := tree.SetActor(actors.InitAddress, act); err != nil { - return cid.Undef, err - } - - return tree.Flush(ctx) -} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 42ea58de7..6aa5d7b97 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -153,7 +153,7 @@ func GetSectorsForElectionPost(ctx context.Context, sm *StateManager, ts *types. copy(uselessBuffer[:], s.CommR) uselessOtherArray = append(uselessOtherArray, ffi.PublicSectorInfo{ SectorNum: s.SectorID, - CommR: uselessBuffer, + CommR: uselessBuffer, }) } diff --git a/chain/sync.go b/chain/sync.go index 8e0c7f842..d41c10edf 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -670,7 +670,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc copy(partial[:], t.Partial) winners = append(winners, sectorbuilder.EPostCandidate{ PartialTicket: partial, - SectorNum: t.SectorID, + SectorNum: t.SectorID, SectorChallengeIndex: t.ChallengeIndex, }) } diff --git a/chain/validation/state.go b/chain/validation/state.go index 8ea8521aa..d16d716af 100644 --- a/chain/validation/state.go +++ b/chain/validation/state.go @@ -20,8 +20,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-crypto" + "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/gen" + "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" @@ -132,7 +133,7 @@ func (s *StateWrapper) SetSingletonActor(addr vactors.SingletonActorID, balance switch lotusAddr { case actors.InitAddress: - initact, err := gen.SetupInitActor(s.bs, nil) + initact, err := genesis.SetupInitActor(s.bs, nil) if err != nil { return nil, nil, err } @@ -142,7 +143,7 @@ func (s *StateWrapper) SetSingletonActor(addr vactors.SingletonActorID, balance return &actorWrapper{*initact}, s.storage, s.flush(tree) case actors.StorageMarketAddress: - nsroot, err := gen.SetupStorageMarketActor(s.bs, s.stateRoot, nil) + nsroot, err := genesis.SetupStorageMarketActor(s.bs, s.stateRoot, nil) if err != nil { return nil, nil, err } @@ -158,7 +159,7 @@ func (s *StateWrapper) SetSingletonActor(addr vactors.SingletonActorID, balance } return &actorWrapper{*smact}, s.storage, s.flush(tree) case actors.StoragePowerAddress: - spact, err := gen.SetupStoragePowerActor(s.bs) + spact, err := genesis.SetupStoragePowerActor(s.bs) if err != nil { return nil, nil, err } diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index 1ef206e55..bff01fee2 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -34,11 +34,11 @@ var log = logging.Logger("preseal") func PreSeal(maddr address.Address, ssize abi.SectorSize, offset abi.SectorNumber, sectors int, sbroot string, preimage []byte) (*genesis.GenesisMiner, error) { cfg := §orbuilder.Config{ - Miner: maddr, - SectorSize: ssize, + Miner: maddr, + SectorSize: ssize, FallbackLastNum: offset, - Paths: sectorbuilder.SimplePath(sbroot), - WorkerThreads: 2, + Paths: sectorbuilder.SimplePath(sbroot), + WorkerThreads: 2, } if err := os.MkdirAll(sbroot, 0775); err != nil { @@ -157,7 +157,7 @@ func createDeals(m *genesis.GenesisMiner, k *wallet.Key, maddr address.Address, PieceSize: abi.PaddedPieceSize(ssize), Client: k.Address, Provider: maddr, - StartEpoch: 1, // TODO: allow setting + StartEpoch: 0, EndEpoch: 9001, StoragePricePerEpoch: big.Zero(), ProviderCollateral: big.Zero(), diff --git a/genesis/types.go b/genesis/types.go index 9a9a34448..484d9d126 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -3,8 +3,8 @@ package genesis import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" ) @@ -12,13 +12,17 @@ type PreSeal struct { CommR [32]byte CommD [32]byte SectorID abi.SectorNumber - Deal actors.StorageDealProposal + Deal market.DealProposal } type GenesisMiner struct { Owner address.Address Worker address.Address + MarketBalance abi.TokenAmount + PowerBalance abi.TokenAmount + WorkerBalance abi.TokenAmount + SectorSize abi.SectorSize Sectors []*PreSeal diff --git a/node/modules/testing/genesis.go b/node/modules/testing/genesis.go index a5cc2e68b..b25a47437 100644 --- a/node/modules/testing/genesis.go +++ b/node/modules/testing/genesis.go @@ -20,7 +20,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/lotus/chain/gen" + + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/genesis" @@ -30,7 +31,7 @@ import ( var glog = logging.Logger("genesis") -func MakeGenesisMem(out io.Writer, gmc *gen.GenMinerCfg) func(bs dtypes.ChainBlockstore, w *wallet.Wallet, syscalls *types.VMSyscalls) modules.Genesis { +func MakeGenesisMem(out io.Writer, gmc *genesis2.GenMinerCfg) func(bs dtypes.ChainBlockstore, w *wallet.Wallet, syscalls *types.VMSyscalls) modules.Genesis { return func(bs dtypes.ChainBlockstore, w *wallet.Wallet, syscalls *types.VMSyscalls) modules.Genesis { return func() (*types.BlockHeader, error) { glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") @@ -51,7 +52,7 @@ func MakeGenesisMem(out io.Writer, gmc *gen.GenMinerCfg) func(bs dtypes.ChainBlo alloc[waddr] = types.FromFil(10000) } - b, err := gen.MakeGenesisBlock(bs, syscalls, alloc, gmc, 100000) + b, err := genesis2.MakeGenesisBlock(bs, syscalls, alloc, gmc, 100000) if err != nil { return nil, err } @@ -101,7 +102,7 @@ func MakeGenesis(outFile, presealInfo, timestamp string) func(bs dtypes.ChainBlo fakePeerIDs = append(fakePeerIDs, peer.ID("peer"+a.String())) } - gmc := &gen.GenMinerCfg{ + gmc := &genesis2.GenMinerCfg{ PeerIDs: fakePeerIDs, PreSeals: preseals, MinerAddrs: minerAddresses, @@ -130,7 +131,7 @@ func MakeGenesis(outFile, presealInfo, timestamp string) func(bs dtypes.ChainBlo ts = uint64(t.Unix()) } - b, err := gen.MakeGenesisBlock(bs, syscalls, addrs, gmc, ts) + b, err := genesis2.MakeGenesisBlock(bs, syscalls, addrs, gmc, ts) if err != nil { return nil, err } diff --git a/node/node_test.go b/node/node_test.go index 71875c96a..c4dac75c2 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -12,7 +12,10 @@ import ( "github.com/filecoin-project/go-address" sectorbuilder "github.com/filecoin-project/go-sectorbuilder" + "github.com/filecoin-project/lotus/build" + genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" + "github.com/filecoin-project/specs-actors/actors/abi" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" @@ -27,7 +30,6 @@ import ( "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" "github.com/filecoin-project/lotus/genesis" @@ -153,7 +155,7 @@ func builder(t *testing.T, nFull int, storage []int) ([]test.TestNode, []test.Te } // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE // TODO: would be great if there was a better way to fake the preseals - gmc := &gen.GenMinerCfg{ + gmc := &genesis2.GenMinerCfg{ PeerIDs: []peer.ID{minerPid}, // TODO: if we have more miners, need more peer IDs PreSeals: map[string]genesis.GenesisMiner{}, } @@ -272,7 +274,7 @@ func mockSbBuilder(t *testing.T, nFull int, storage []int) ([]test.TestNode, []t } // PRESEAL SECTION, TRY TO REPLACE WITH BETTER IN THE FUTURE // TODO: would be great if there was a better way to fake the preseals - gmc := &gen.GenMinerCfg{ + gmc := &genesis2.GenMinerCfg{ PeerIDs: []peer.ID{minerPid}, // TODO: if we have more miners, need more peer IDs PreSeals: map[string]genesis.GenesisMiner{}, } diff --git a/storage/sealing/garbage.go b/storage/sealing/garbage.go index 89f7f64cb..914de414a 100644 --- a/storage/sealing/garbage.go +++ b/storage/sealing/garbage.go @@ -10,6 +10,7 @@ import ( commcid "github.com/filecoin-project/go-fil-commcid" "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "golang.org/x/xerrors" @@ -65,7 +66,7 @@ func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorNumber, e log.Infof("Publishing deals for %d", sectorID) - params, aerr := actors.SerializeParams(&actors.PublishStorageDealsParams{ + params, aerr := actors.SerializeParams(&market.PublishStorageDealsParams{ Deals: deals, }) if aerr != nil { @@ -78,7 +79,7 @@ func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorNumber, e Value: types.NewInt(0), GasPrice: types.NewInt(0), GasLimit: types.NewInt(1000000), - Method: actors.SMAMethods.PublishStorageDeals, + Method: builtin.MethodsMarket.PublishStorageDeals, Params: params, }) if err != nil {