github.com/filecoin-project/specs-actors/v4@v4.0.2/support/agent/miner_generator.go (about)

     1  package agent
     2  
     3  import (
     4  	"math/rand"
     5  
     6  	"github.com/filecoin-project/go-address"
     7  	"github.com/filecoin-project/go-state-types/cbor"
     8  	"github.com/pkg/errors"
     9  
    10  	power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power"
    11  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    12  	"github.com/filecoin-project/specs-actors/v4/actors/builtin/power"
    13  	power3 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power"
    14  )
    15  
    16  // MinerGenerator adds miner agents to the simulation at a configured rate.
    17  // When triggered to add a new miner, it:
    18  // * Selects the next owner address from the accounts it has been given.
    19  // * Sends a createMiner message from that account
    20  // * Handles the response by creating a MinerAgent with MinerAgentConfig and registering it in the sim.
    21  type MinerGenerator struct {
    22  	config            MinerAgentConfig // eventually this should become a set of probabilities to support miner differentiation
    23  	createMinerEvents *RateIterator
    24  	minersCreated     int
    25  	accounts          []address.Address
    26  	rnd               *rand.Rand
    27  }
    28  
    29  func NewMinerGenerator(accounts []address.Address, config MinerAgentConfig, createMinerRate float64, rndSeed int64) *MinerGenerator {
    30  	rnd := rand.New(rand.NewSource(rndSeed))
    31  	return &MinerGenerator{
    32  		config:            config,
    33  		createMinerEvents: NewRateIterator(createMinerRate, rnd.Int63()),
    34  		accounts:          accounts,
    35  		rnd:               rnd,
    36  	}
    37  }
    38  
    39  func (mg *MinerGenerator) Tick(s SimState) ([]message, error) {
    40  	var msgs []message
    41  	if mg.minersCreated >= len(mg.accounts) {
    42  		return msgs, nil
    43  	}
    44  
    45  	err := mg.createMinerEvents.Tick(func() error {
    46  		if mg.minersCreated < len(mg.accounts) {
    47  			addr := mg.accounts[mg.minersCreated]
    48  			mg.minersCreated++
    49  			msg, err := mg.createMiner(addr, mg.config, s)
    50  			if err != nil {
    51  				return err
    52  			}
    53  			msgs = append(msgs, msg)
    54  		}
    55  		return nil
    56  	})
    57  	return msgs, err
    58  }
    59  
    60  func (mg *MinerGenerator) createMiner(owner address.Address, cfg MinerAgentConfig, s SimState) (message, error) {
    61  	params, err := s.CreateMinerParams(owner, owner, cfg.ProofType)
    62  	if err != nil {
    63  		return message{}, err
    64  	}
    65  	return message{
    66  		From:   owner,
    67  		To:     builtin.StoragePowerActorAddr,
    68  		Value:  mg.config.StartingBalance, // miner gets all account funds
    69  		Method: builtin.MethodsPower.CreateMiner,
    70  		Params: params,
    71  		ReturnHandler: func(s SimState, msg message, ret cbor.Marshaler) error {
    72  			createMinerRet, ok := ret.(*power.CreateMinerReturn)
    73  			if !ok {
    74  				return errors.Errorf("create miner return has wrong type: %v", ret)
    75  			}
    76  
    77  			var worker, owner address.Address
    78  			params, okV3 := msg.Params.(*power3.CreateMinerParams)
    79  			if !okV3 {
    80  				params, okV2 := msg.Params.(*power2.CreateMinerParams)
    81  				if !okV2 {
    82  					return errors.Errorf("create miner params has wrong type: %v", msg.Params)
    83  				}
    84  				worker = params.Worker
    85  				owner = params.Owner
    86  			} else {
    87  				worker = params.Worker
    88  				owner = params.Owner
    89  			}
    90  
    91  			// register agent as both a miner and deal provider
    92  			minerAgent := NewMinerAgent(owner, worker, createMinerRet.IDAddress, createMinerRet.RobustAddress, mg.rnd.Int63(), cfg)
    93  			s.AddAgent(minerAgent)
    94  			s.AddDealProvider(minerAgent)
    95  			return nil
    96  		},
    97  	}, nil
    98  }