package builders import ( "context" "log" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/actors/abi" abi_spec "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/account" "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/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" ) // Actors is an object that manages actors in the test vector. type Actors struct { accounts []AddressHandle miners []AddressHandle b *Builder } // AccountN creates many account actors of the specified kind, with the // specified balance, and places their addresses in the supplied AddressHandles. func (a *Actors) AccountN(typ address.Protocol, balance abi.TokenAmount, handles ...*AddressHandle) { for _, handle := range handles { h := a.Account(typ, balance) *handle = h } } // Account creates a single account actor of the specified kind, with the // specified balance, and returns its AddressHandle. func (a *Actors) Account(typ address.Protocol, balance abi.TokenAmount) AddressHandle { a.b.Assert.In(typ, address.SECP256K1, address.BLS) var addr address.Address switch typ { case address.SECP256K1: addr = a.b.Wallet.NewSECP256k1Account() case address.BLS: addr = a.b.Wallet.NewBLSAccount() } actorState := &account.State{Address: addr} handle := a.CreateActor(builtin.AccountActorCodeID, addr, balance, actorState) a.accounts = append(a.accounts, handle) return handle } type MinerActorCfg struct { SealProofType abi.RegisteredSealProof PeriodBoundary abi.ChainEpoch OwnerBalance abi.TokenAmount } // Miner creates an owner account, a worker account, and a miner actor managed // by those accounts. func (a *Actors) Miner(cfg MinerActorCfg) (minerActor, owner, worker AddressHandle) { owner = a.Account(address.SECP256K1, cfg.OwnerBalance) worker = a.Account(address.BLS, big.Zero()) // expectedMinerActorIDAddress := chain.MustNewIDAddr(chain.MustIDFromAddress(minerWorkerID) + 1) // minerActorAddrs := computeInitActorExecReturn(minerWorkerPk, 0, 1, expectedMinerActorIDAddress) ss, err := cfg.SealProofType.SectorSize() a.b.Assert.NoError(err, "seal proof sector size") ps, err := cfg.SealProofType.WindowPoStPartitionSectors() a.b.Assert.NoError(err, "seal proof window PoSt partition sectors") mi := &miner.MinerInfo{ Owner: owner.ID, Worker: worker.ID, PendingWorkerKey: nil, PeerId: abi.PeerID("chain-validation"), Multiaddrs: nil, SealProofType: cfg.SealProofType, SectorSize: ss, WindowPoStPartitionSectors: ps, } infoCid, err := a.b.Stores.CBORStore.Put(context.Background(), mi) if err != nil { panic(err) } // create the miner actor s.t. it exists in the init actors map minerState, err := miner.ConstructState(infoCid, cfg.PeriodBoundary, EmptyBitfieldCid, EmptyArrayCid, EmptyMapCid, EmptyDeadlinesCid, ) if err != nil { panic(err) } minerActorAddr := worker.NextActorAddress(0, 0) handle := a.CreateActor(builtin.StorageMinerActorCodeID, minerActorAddr, big.Zero(), minerState) // assert miner actor has been created, exists in the state tree, and has an entry in the init actor. // next update the storage power actor to track the miner var spa power.State a.ActorState(builtin.StoragePowerActorAddr, &spa) // set the miners claim hm, err := adt.AsMap(adt.WrapStore(context.Background(), a.b.Stores.CBORStore), spa.Claims) if err != nil { panic(err) } // add claim for the miner err = hm.Put(adt.AddrKey(handle.ID), &power.Claim{ RawBytePower: abi.NewStoragePower(0), QualityAdjPower: abi.NewTokenAmount(0), }) if err != nil { panic(err) } // save the claim spa.Claims, err = hm.Root() if err != nil { panic(err) } // update miner count spa.MinerCount += 1 // update storage power actor's state in the tree _, err = a.b.Stores.CBORStore.Put(context.Background(), &spa) if err != nil { panic(err) } a.miners = append(a.miners, handle) return handle, owner, worker } // CreateActor creates an actor in the state tree, of the specified kind, with // the specified address and balance, and sets its state to the supplied state. func (a *Actors) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, state runtime.CBORMarshaler) AddressHandle { var id address.Address if addr.Protocol() != address.ID { var err error id, err = a.b.StateTree.RegisterNewAddress(addr) if err != nil { log.Panicf("register new address for actor: %v", err) } } // Store the new state. head, err := a.b.StateTree.Store.Put(context.Background(), state) if err != nil { panic(err) } // Set the actor's head to point to that state. actr := &types.Actor{ Code: code, Head: head, Balance: balance, } if err := a.b.StateTree.SetActor(addr, actr); err != nil { log.Panicf("setting new actor for actor: %v", err) } return AddressHandle{id, addr} } // ActorState retrieves the state of the supplied actor, and sets it in the // provided object. It also returns the actor's header from the state tree. func (a *Actors) ActorState(addr address.Address, out cbg.CBORUnmarshaler) *types.Actor { actor := a.Header(addr) err := a.b.StateTree.Store.Get(context.Background(), actor.Head, out) a.b.Assert.NoError(err, "failed to load state for actorr %s; head=%s", addr, actor.Head) return actor } // Header returns the actor's header from the state tree. func (a *Actors) Header(addr address.Address) *types.Actor { actor, err := a.b.StateTree.GetActor(addr) a.b.Assert.NoError(err, "failed to fetch actor %s from state", addr) return actor } // Balance is a shortcut for Header(addr).Balance. func (a *Actors) Balance(addr address.Address) abi_spec.TokenAmount { return a.Header(addr).Balance } // Head is a shortcut for Header(addr).Head. func (a *Actors) Head(addr address.Address) cid.Cid { return a.Header(addr).Head } // Nonce is a shortcut for Header(addr).Nonce. func (a *Actors) Nonce(addr address.Address) uint64 { return a.Header(addr).Nonce } // Code is a shortcut for Header(addr).Code. func (a *Actors) Code(addr address.Address) cid.Cid { return a.Header(addr).Code }