2019-12-19 18:46:30 +00:00
package stmgr
import (
2020-09-24 21:30:11 +00:00
"bytes"
2019-12-19 18:46:30 +00:00
"context"
2020-09-24 21:30:11 +00:00
"encoding/binary"
2021-01-26 20:46:57 +00:00
"sort"
2021-01-26 23:11:31 +00:00
"sync"
2021-01-27 23:05:00 +00:00
"time"
2020-09-24 21:30:11 +00:00
2022-04-04 09:03:48 +00:00
"github.com/filecoin-project/specs-actors/v8/actors/migration/nv16"
2021-12-20 01:44:19 +00:00
2021-07-27 12:48:30 +00:00
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
2021-01-19 07:34:08 +00:00
2020-09-05 03:01:36 +00:00
"github.com/filecoin-project/go-address"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
2020-09-05 03:01:36 +00:00
"github.com/filecoin-project/go-state-types/big"
2020-10-01 22:02:40 +00:00
"github.com/filecoin-project/go-state-types/network"
2020-09-28 22:54:48 +00:00
"github.com/filecoin-project/lotus/chain/actors/adt"
2020-11-19 06:47:13 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin"
2020-09-28 22:54:48 +00:00
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
2020-09-28 21:25:58 +00:00
"github.com/filecoin-project/lotus/chain/state"
2020-07-28 12:31:13 +00:00
"github.com/filecoin-project/lotus/chain/types"
2020-09-24 21:30:11 +00:00
"github.com/filecoin-project/lotus/chain/vm"
2019-12-19 18:46:30 +00:00
)
2021-01-26 20:46:57 +00:00
// MigrationCache can be used to cache information used by a migration. This is primarily useful to
// "pre-compute" some migration state ahead of time, and make it accessible in the migration itself.
type MigrationCache interface {
Write ( key string , value cid . Cid ) error
Read ( key string ) ( bool , cid . Cid , error )
Load ( key string , loadFunc func ( ) ( cid . Cid , error ) ) ( cid . Cid , error )
}
2021-01-26 23:15:14 +00:00
// MigrationFunc is a migration function run at every upgrade.
2020-10-07 20:56:38 +00:00
//
2021-01-26 20:46:57 +00:00
// - The cache is a per-upgrade cache, pre-populated by pre-migrations.
2020-10-07 20:56:38 +00:00
// - The oldState is the state produced by the upgrade epoch.
// - The returned newState is the new state that will be used by the next epoch.
// - The height is the upgrade epoch height (already executed).
2021-08-27 00:23:04 +00:00
// - The tipset is the first non-null tipset after the upgrade height (the tipset in
// which the upgrade is executed). Do not assume that ts.Height() is the upgrade height.
//
// NOTE: In StateCompute and CallWithGas, the passed tipset is actually the tipset _before_ the
// upgrade. The tipset should really only be used for referencing the "current chain".
2021-01-26 23:15:14 +00:00
type MigrationFunc func (
2021-01-26 20:46:57 +00:00
ctx context . Context ,
sm * StateManager , cache MigrationCache ,
2022-04-04 09:03:48 +00:00
cb ExecMonitor ,
manifest cid . Cid ,
oldState cid . Cid ,
2021-01-26 20:46:57 +00:00
height abi . ChainEpoch , ts * types . TipSet ,
) ( newState cid . Cid , err error )
2021-01-26 23:15:14 +00:00
// PreMigrationFunc is a function run _before_ a network upgrade to pre-compute part of the network
2021-01-26 20:46:57 +00:00
// upgrade and speed it up.
2021-01-26 23:15:14 +00:00
type PreMigrationFunc func (
2021-01-26 20:46:57 +00:00
ctx context . Context ,
sm * StateManager , cache MigrationCache ,
2022-04-04 09:03:48 +00:00
manifest cid . Cid ,
2021-01-26 20:46:57 +00:00
oldState cid . Cid ,
height abi . ChainEpoch , ts * types . TipSet ,
2021-01-26 22:57:38 +00:00
) error
2021-01-26 20:46:57 +00:00
2021-01-26 23:15:14 +00:00
// PreMigration describes a pre-migration step to prepare for a network state upgrade. Pre-migrations
2021-01-26 20:46:57 +00:00
// are optimizations, are not guaranteed to run, and may be canceled and/or run multiple times.
2021-01-26 23:15:14 +00:00
type PreMigration struct {
// PreMigration is the pre-migration function to run at the specified time. This function is
2021-01-26 23:05:12 +00:00
// run asynchronously and must abort promptly when canceled.
2021-01-26 23:15:14 +00:00
PreMigration PreMigrationFunc
2021-01-26 20:46:57 +00:00
2021-01-27 23:58:51 +00:00
// StartWithin specifies that this pre-migration should be started at most StartWithin
// epochs before the upgrade.
StartWithin abi . ChainEpoch
2021-01-26 20:46:57 +00:00
2021-01-27 23:58:51 +00:00
// DontStartWithin specifies that this pre-migration should not be started DontStartWithin
// epochs before the final upgrade epoch.
2021-01-26 20:46:57 +00:00
//
2021-01-27 23:58:51 +00:00
// This should be set such that the pre-migration is likely to complete before StopWithin.
DontStartWithin abi . ChainEpoch
// StopWithin specifies that this pre-migration should be stopped StopWithin epochs of the
// final upgrade epoch.
StopWithin abi . ChainEpoch
2021-01-26 20:46:57 +00:00
}
2020-10-01 22:02:40 +00:00
type Upgrade struct {
Height abi . ChainEpoch
2020-10-03 00:09:56 +00:00
Network network . Version
2020-10-07 23:14:11 +00:00
Expensive bool
2021-01-26 23:15:14 +00:00
Migration MigrationFunc
2021-01-26 20:46:57 +00:00
2021-01-26 23:15:14 +00:00
// PreMigrations specifies a set of pre-migration functions to run at the indicated epochs.
2021-01-26 20:46:57 +00:00
// These functions should fill the given cache with information that can speed up the
// eventual full migration at the upgrade epoch.
2021-01-26 23:15:14 +00:00
PreMigrations [ ] PreMigration
2022-04-04 09:03:48 +00:00
// Manifest is the migration manifest CID, starting with nv16; for older migrations it is
// undefined
Manifest cid . Cid
2020-10-01 22:02:40 +00:00
}
2020-10-03 00:09:56 +00:00
type UpgradeSchedule [ ] Upgrade
2020-10-01 22:02:40 +00:00
2020-10-03 00:09:56 +00:00
func ( us UpgradeSchedule ) Validate ( ) error {
2021-01-26 23:00:55 +00:00
// Make sure each upgrade is valid.
2020-10-03 00:09:56 +00:00
for _ , u := range us {
if u . Network <= 0 {
return xerrors . Errorf ( "cannot upgrade to version <= 0: %d" , u . Network )
}
2021-01-26 23:00:55 +00:00
2021-01-26 23:15:14 +00:00
for _ , m := range u . PreMigrations {
2021-01-27 23:58:51 +00:00
if m . StartWithin <= 0 {
return xerrors . Errorf ( "pre-migration must specify a positive start-within epoch" )
}
if m . DontStartWithin < 0 || m . StopWithin < 0 {
2021-01-27 20:24:48 +00:00
return xerrors . Errorf ( "pre-migration must specify non-negative epochs" )
}
2021-01-27 23:58:51 +00:00
if m . StartWithin <= m . StopWithin {
return xerrors . Errorf ( "pre-migration start-within must come before stop-within" )
}
// If we have a dont-start-within.
if m . DontStartWithin != 0 {
if m . DontStartWithin < m . StopWithin {
return xerrors . Errorf ( "pre-migration dont-start-within must come before stop-within" )
}
if m . StartWithin <= m . DontStartWithin {
return xerrors . Errorf ( "pre-migration start-within must come after dont-start-within" )
}
2021-01-26 23:00:55 +00:00
}
}
2021-01-27 20:24:48 +00:00
if ! sort . SliceIsSorted ( u . PreMigrations , func ( i , j int ) bool {
2021-01-27 23:58:51 +00:00
return u . PreMigrations [ i ] . StartWithin > u . PreMigrations [ j ] . StartWithin //nolint:scopelint,gosec
2021-01-27 20:24:48 +00:00
} ) {
return xerrors . Errorf ( "pre-migrations must be sorted by start epoch" )
}
2020-10-03 00:09:56 +00:00
}
2021-01-26 23:00:55 +00:00
// Make sure the upgrade order makes sense.
2020-10-03 00:09:56 +00:00
for i := 1 ; i < len ( us ) ; i ++ {
prev := & us [ i - 1 ]
curr := & us [ i ]
if ! ( prev . Network <= curr . Network ) {
return xerrors . Errorf ( "cannot downgrade from version %d to version %d" , prev . Network , curr . Network )
}
// Make sure the heights make sense.
if prev . Height < 0 {
// Previous upgrade was disabled.
continue
}
if ! ( prev . Height < curr . Height ) {
return xerrors . Errorf ( "upgrade heights must be strictly increasing: upgrade %d was at height %d, followed by upgrade %d at height %d" , i - 1 , prev . Height , i , curr . Height )
}
}
return nil
2020-09-05 03:01:36 +00:00
}
2020-01-31 23:51:15 +00:00
2021-07-20 16:02:52 +00:00
func ( us UpgradeSchedule ) GetNtwkVersion ( e abi . ChainEpoch ) ( network . Version , error ) {
// Traverse from newest to oldest returning upgrade active during epoch e
for i := len ( us ) - 1 ; i >= 0 ; i -- {
u := us [ i ]
// u.Height is the last epoch before u.Network becomes the active version
if u . Height < e {
return u . Network , nil
}
}
2022-03-25 19:09:14 +00:00
return build . GenesisNetworkVersion , nil
2021-07-20 16:02:52 +00:00
}
2021-09-02 16:07:23 +00:00
func ( sm * StateManager ) HandleStateForks ( ctx context . Context , root cid . Cid , height abi . ChainEpoch , cb ExecMonitor , ts * types . TipSet ) ( cid . Cid , error ) {
2020-09-24 21:30:11 +00:00
retCid := root
var err error
2021-01-26 20:46:57 +00:00
u := sm . stateMigrations [ height ]
if u != nil && u . upgrade != nil {
2021-01-27 23:05:00 +00:00
startTime := time . Now ( )
2021-01-28 19:17:09 +00:00
log . Warnw ( "STARTING migration" , "height" , height , "from" , root )
2021-01-27 01:08:06 +00:00
// Yes, we clone the cache, even for the final upgrade epoch. Why? Reverts. We may
// have to migrate multiple times.
tmpCache := u . cache . Clone ( )
2022-04-04 09:03:48 +00:00
retCid , err = u . upgrade ( ctx , sm , tmpCache , cb , u . manifest , root , height , ts )
2020-07-28 12:31:13 +00:00
if err != nil {
2021-01-28 19:17:09 +00:00
log . Errorw ( "FAILED migration" , "height" , height , "from" , root , "error" , err )
2020-09-24 21:30:11 +00:00
return cid . Undef , err
2019-12-19 20:00:59 +00:00
}
2021-01-27 01:08:06 +00:00
// Yes, we update the cache, even for the final upgrade epoch. Why? Reverts. This
// can save us a _lot_ of time because very few actors will have changed if we
// do a small revert then need to re-run the migration.
u . cache . Update ( tmpCache )
2021-01-27 23:05:00 +00:00
log . Warnw ( "COMPLETED migration" ,
"height" , height ,
2021-01-28 19:17:09 +00:00
"from" , root ,
"to" , retCid ,
2021-01-27 23:05:00 +00:00
"duration" , time . Since ( startTime ) ,
)
2019-12-19 18:46:30 +00:00
}
2019-12-19 20:00:59 +00:00
2020-09-24 21:30:11 +00:00
return retCid , nil
2019-12-19 18:46:30 +00:00
}
2020-09-05 03:01:36 +00:00
2021-08-30 23:20:23 +00:00
// Returns true executing tipsets between the specified heights would trigger an expensive
2021-08-31 17:37:51 +00:00
// migration. NOTE: migrations occurring _at_ the target height are not included, as they're
// executed _after_ the target height.
2021-08-27 00:23:04 +00:00
func ( sm * StateManager ) hasExpensiveForkBetween ( parent , height abi . ChainEpoch ) bool {
for h := parent ; h < height ; h ++ {
if _ , ok := sm . expensiveUpgrades [ h ] ; ok {
return true
}
}
return false
}
func ( sm * StateManager ) hasExpensiveFork ( height abi . ChainEpoch ) bool {
2020-10-07 23:14:11 +00:00
_ , ok := sm . expensiveUpgrades [ height ]
2020-10-07 21:35:07 +00:00
return ok
}
2022-04-04 09:03:48 +00:00
func runPreMigration ( ctx context . Context , sm * StateManager , manifest cid . Cid , fn PreMigrationFunc , cache * nv16 . MemMigrationCache , ts * types . TipSet ) {
2021-01-27 23:05:00 +00:00
height := ts . Height ( )
parent := ts . ParentState ( )
startTime := time . Now ( )
log . Warn ( "STARTING pre-migration" )
2021-01-27 02:50:25 +00:00
// Clone the cache so we don't actually _update_ it
// till we're done. Otherwise, if we fail, the next
// migration to use the cache may assume that
// certain blocks exist, even if they don't.
tmpCache := cache . Clone ( )
2022-04-04 09:03:48 +00:00
err := fn ( ctx , sm , tmpCache , manifest , parent , height , ts )
2021-01-27 02:50:25 +00:00
if err != nil {
2021-01-27 23:05:00 +00:00
log . Errorw ( "FAILED pre-migration" , "error" , err )
2021-01-27 02:50:25 +00:00
return
}
// Finally, if everything worked, update the cache.
cache . Update ( tmpCache )
2021-01-27 23:05:00 +00:00
log . Warnw ( "COMPLETED pre-migration" , "duration" , time . Since ( startTime ) )
2021-01-27 02:50:25 +00:00
}
2021-01-26 20:46:57 +00:00
func ( sm * StateManager ) preMigrationWorker ( ctx context . Context ) {
2021-01-26 23:11:31 +00:00
defer close ( sm . shutdown )
2021-01-26 20:46:57 +00:00
ctx , cancel := context . WithCancel ( ctx )
defer cancel ( )
type op struct {
2021-01-26 22:57:38 +00:00
after abi . ChainEpoch
notAfter abi . ChainEpoch
2021-01-26 23:05:12 +00:00
run func ( ts * types . TipSet )
2021-01-26 20:46:57 +00:00
}
2021-01-26 23:11:31 +00:00
var wg sync . WaitGroup
defer wg . Wait ( )
2021-01-26 20:46:57 +00:00
// Turn each pre-migration into an operation in a schedule.
var schedule [ ] op
2021-01-26 22:57:38 +00:00
for upgradeEpoch , migration := range sm . stateMigrations {
2021-01-26 20:46:57 +00:00
cache := migration . cache
for _ , prem := range migration . preMigrations {
preCtx , preCancel := context . WithCancel ( ctx )
2021-01-26 23:15:14 +00:00
migrationFunc := prem . PreMigration
2021-01-26 20:46:57 +00:00
2021-01-27 23:58:51 +00:00
afterEpoch := upgradeEpoch - prem . StartWithin
notAfterEpoch := upgradeEpoch - prem . DontStartWithin
stopEpoch := upgradeEpoch - prem . StopWithin
// We can't start after we stop.
if notAfterEpoch > stopEpoch {
notAfterEpoch = stopEpoch - 1
}
2021-01-26 22:57:38 +00:00
2021-01-26 20:46:57 +00:00
// Add an op to start a pre-migration.
schedule = append ( schedule , op {
2021-01-26 22:57:38 +00:00
after : afterEpoch ,
notAfter : notAfterEpoch ,
2021-01-26 20:46:57 +00:00
// TODO: are these values correct?
2021-01-26 23:05:12 +00:00
run : func ( ts * types . TipSet ) {
2021-01-26 23:11:31 +00:00
wg . Add ( 1 )
2021-01-26 23:05:12 +00:00
go func ( ) {
2021-01-26 23:11:31 +00:00
defer wg . Done ( )
2022-04-04 09:03:48 +00:00
runPreMigration ( preCtx , sm , migration . manifest , migrationFunc , cache , ts )
2021-01-26 23:05:12 +00:00
} ( )
2021-01-26 22:57:38 +00:00
} ,
2021-01-26 20:46:57 +00:00
} )
2021-01-26 22:57:38 +00:00
// Add an op to cancel the pre-migration if it's still running.
2021-01-26 20:46:57 +00:00
schedule = append ( schedule , op {
2021-01-27 23:58:51 +00:00
after : stopEpoch ,
2021-01-26 22:57:38 +00:00
notAfter : - 1 ,
2021-01-26 23:05:12 +00:00
run : func ( ts * types . TipSet ) { preCancel ( ) } ,
2021-01-26 20:46:57 +00:00
} )
}
}
// Then sort by epoch.
sort . Slice ( schedule , func ( i , j int ) bool {
2021-01-26 22:57:38 +00:00
return schedule [ i ] . after < schedule [ j ] . after
2021-01-26 20:46:57 +00:00
} )
// Finally, when the head changes, see if there's anything we need to do.
2021-01-27 23:58:51 +00:00
//
// We're intentionally ignoring reorgs as they don't matter for our purposes.
2021-01-26 20:46:57 +00:00
for change := range sm . cs . SubHeadChanges ( ctx ) {
for _ , head := range change {
for len ( schedule ) > 0 {
2021-01-26 22:57:38 +00:00
op := & schedule [ 0 ]
if head . Val . Height ( ) < op . after {
2021-01-26 20:46:57 +00:00
break
}
2021-01-26 22:57:38 +00:00
// If we haven't passed the pre-migration height...
2021-01-27 23:58:51 +00:00
if op . notAfter < 0 || head . Val . Height ( ) < op . notAfter {
2021-01-26 23:05:12 +00:00
op . run ( head . Val )
2021-01-26 22:57:38 +00:00
}
2021-01-26 20:46:57 +00:00
schedule = schedule [ 1 : ]
}
}
}
}
2021-09-02 16:07:23 +00:00
func DoTransfer ( tree types . StateTree , from , to address . Address , amt abi . TokenAmount , cb func ( trace types . ExecutionTrace ) ) error {
2020-09-05 03:01:36 +00:00
fromAct , err := tree . GetActor ( from )
if err != nil {
return xerrors . Errorf ( "failed to get 'from' actor for transfer: %w" , err )
}
fromAct . Balance = types . BigSub ( fromAct . Balance , amt )
if fromAct . Balance . Sign ( ) < 0 {
return xerrors . Errorf ( "(sanity) deducted more funds from target account than it had (%s, %s)" , from , types . FIL ( amt ) )
}
if err := tree . SetActor ( from , fromAct ) ; err != nil {
return xerrors . Errorf ( "failed to persist from actor: %w" , err )
}
toAct , err := tree . GetActor ( to )
if err != nil {
return xerrors . Errorf ( "failed to get 'to' actor for transfer: %w" , err )
}
toAct . Balance = types . BigAdd ( toAct . Balance , amt )
if err := tree . SetActor ( to , toAct ) ; err != nil {
return xerrors . Errorf ( "failed to persist to actor: %w" , err )
}
2020-09-24 21:30:11 +00:00
if cb != nil {
// record the transfer in execution traces
2020-10-13 05:20:49 +00:00
cb ( types . ExecutionTrace {
2021-09-02 16:07:23 +00:00
Msg : MakeFakeMsg ( from , to , amt , 0 ) ,
MsgRct : MakeFakeRct ( ) ,
2020-10-13 05:20:49 +00:00
Error : "" ,
Duration : 0 ,
GasCharges : nil ,
Subcalls : nil ,
} )
2020-09-24 21:30:11 +00:00
}
2020-09-05 03:01:36 +00:00
return nil
}
2021-09-02 16:07:23 +00:00
func TerminateActor ( ctx context . Context , tree * state . StateTree , addr address . Address , em ExecMonitor , epoch abi . ChainEpoch , ts * types . TipSet ) error {
2021-02-18 03:41:58 +00:00
a , err := tree . GetActor ( addr )
if xerrors . Is ( err , types . ErrActorNotFound ) {
return types . ErrActorNotFound
2021-02-19 07:03:00 +00:00
} else if err != nil {
return xerrors . Errorf ( "failed to get actor to delete: %w" , err )
2021-02-18 03:41:58 +00:00
}
var trace types . ExecutionTrace
2021-09-02 16:07:23 +00:00
if err := DoTransfer ( tree , addr , builtin . BurntFundsActorAddr , a . Balance , func ( t types . ExecutionTrace ) {
2021-02-18 03:41:58 +00:00
trace = t
} ) ; err != nil {
return xerrors . Errorf ( "transferring terminated actor's balance: %w" , err )
}
2021-06-04 00:44:38 +00:00
if em != nil {
2021-02-18 03:41:58 +00:00
// record the transfer in execution traces
2021-09-02 16:07:23 +00:00
fakeMsg := MakeFakeMsg ( builtin . SystemActorAddr , addr , big . Zero ( ) , uint64 ( epoch ) )
2021-02-18 03:41:58 +00:00
2021-06-04 00:44:38 +00:00
if err := em . MessageApplied ( ctx , ts , fakeMsg . Cid ( ) , fakeMsg , & vm . ApplyRet {
2021-09-02 16:07:23 +00:00
MessageReceipt : * MakeFakeRct ( ) ,
2021-02-18 03:41:58 +00:00
ActorErr : nil ,
ExecutionTrace : trace ,
Duration : 0 ,
GasCosts : nil ,
2021-06-04 00:44:38 +00:00
} , false ) ; err != nil {
2021-02-18 03:41:58 +00:00
return xerrors . Errorf ( "recording transfers: %w" , err )
}
}
2021-02-18 22:16:32 +00:00
err = tree . DeleteActor ( addr )
if err != nil {
return xerrors . Errorf ( "deleting actor from tree: %w" , err )
}
ia , err := tree . GetActor ( init_ . Address )
if err != nil {
return xerrors . Errorf ( "loading init actor: %w" , err )
}
2021-02-19 07:03:00 +00:00
ias , err := init_ . Load ( & state . AdtStore { IpldStore : tree . Store } , ia )
2021-02-18 22:16:32 +00:00
if err != nil {
return xerrors . Errorf ( "loading init actor state: %w" , err )
}
2021-02-19 07:03:00 +00:00
if err := ias . Remove ( addr ) ; err != nil {
2021-02-18 22:16:32 +00:00
return xerrors . Errorf ( "deleting entry from address map: %w" , err )
}
2021-02-19 07:03:00 +00:00
nih , err := tree . Store . Put ( ctx , ias )
2021-02-18 22:16:32 +00:00
if err != nil {
return xerrors . Errorf ( "writing new init actor state: %w" , err )
}
ia . Head = nih
return tree . SetActor ( init_ . Address , ia )
2021-02-18 03:41:58 +00:00
}
2021-09-02 16:07:23 +00:00
func SetNetworkName ( ctx context . Context , store adt . Store , tree * state . StateTree , name string ) error {
2021-07-27 12:48:30 +00:00
ia , err := tree . GetActor ( init_ . Address )
2020-09-24 21:30:11 +00:00
if err != nil {
return xerrors . Errorf ( "getting init actor: %w" , err )
}
2020-09-28 22:54:48 +00:00
initState , err := init_ . Load ( store , ia )
if err != nil {
2020-09-24 21:30:11 +00:00
return xerrors . Errorf ( "reading init state: %w" , err )
}
2020-09-28 22:59:11 +00:00
if err := initState . SetNetworkName ( name ) ; err != nil {
return xerrors . Errorf ( "setting network name: %w" , err )
}
2020-09-24 21:30:11 +00:00
2020-09-28 22:54:48 +00:00
ia . Head , err = store . Put ( ctx , initState )
2020-09-24 21:30:11 +00:00
if err != nil {
return xerrors . Errorf ( "writing new init state: %w" , err )
}
2021-07-27 12:48:30 +00:00
if err := tree . SetActor ( init_ . Address , ia ) ; err != nil {
2020-09-24 21:30:11 +00:00
return xerrors . Errorf ( "setting init actor: %w" , err )
}
return nil
}
2021-09-02 16:07:23 +00:00
func MakeKeyAddr ( splitAddr address . Address , count uint64 ) ( address . Address , error ) {
2020-09-24 21:30:11 +00:00
var b bytes . Buffer
if err := splitAddr . MarshalCBOR ( & b ) ; err != nil {
return address . Undef , xerrors . Errorf ( "marshalling split address: %w" , err )
}
if err := binary . Write ( & b , binary . BigEndian , count ) ; err != nil {
return address . Undef , xerrors . Errorf ( "writing count into a buffer: %w" , err )
}
if err := binary . Write ( & b , binary . BigEndian , [ ] byte ( "Ignition upgrade" ) ) ; err != nil {
return address . Undef , xerrors . Errorf ( "writing fork name into a buffer: %w" , err )
}
addr , err := address . NewActorAddress ( b . Bytes ( ) )
if err != nil {
return address . Undef , xerrors . Errorf ( "create actor address: %w" , err )
}
return addr , nil
}
2021-09-02 16:07:23 +00:00
func MakeFakeMsg ( from address . Address , to address . Address , amt abi . TokenAmount , nonce uint64 ) * types . Message {
2021-02-18 03:41:58 +00:00
return & types . Message {
From : from ,
To : to ,
Value : amt ,
Nonce : nonce ,
}
}
2021-02-19 07:03:00 +00:00
2021-09-02 16:07:23 +00:00
func MakeFakeRct ( ) * types . MessageReceipt {
2021-02-19 07:03:00 +00:00
return & types . MessageReceipt {
ExitCode : 0 ,
Return : nil ,
GasUsed : 0 ,
}
}