lotus/tvx/builders/actors.go
Raúl Kripalani 99f466e35e
test vector builder API + partial migration of suites (#229)
Co-authored-by: Anton Evangelatov <anton.evangelatov@gmail.com>
2020-08-14 13:51:43 +01:00

214 lines
6.5 KiB
Go

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
}