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"
"math"
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 21:25:58 +00:00
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"golang.org/x/xerrors"
2020-09-22 18:14:55 +00:00
2020-09-22 19:02:29 +00:00
builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
2020-09-22 18:14:55 +00:00
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
2020-09-28 21:25:58 +00:00
multisig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
2020-09-22 18:14:55 +00:00
power0 "github.com/filecoin-project/specs-actors/actors/builtin/power"
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
2020-09-28 21:25:58 +00:00
"github.com/filecoin-project/specs-actors/actors/migration/nv3"
2020-09-28 22:50:54 +00:00
m2 "github.com/filecoin-project/specs-actors/v2/actors/migration"
2020-09-29 00:42:29 +00:00
states2 "github.com/filecoin-project/specs-actors/v2/actors/states"
2020-09-28 21:25:58 +00:00
2020-09-05 03:01:36 +00:00
"github.com/filecoin-project/lotus/build"
2020-09-28 22:50:54 +00:00
"github.com/filecoin-project/lotus/chain/actors"
2020-09-28 22:54:48 +00:00
"github.com/filecoin-project/lotus/chain/actors/adt"
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
2020-09-28 21:25:58 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"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
)
2020-10-01 22:02:40 +00:00
type UpgradeFunc func ( context . Context , * StateManager , ExecCallback , cid . Cid , * types . TipSet ) ( cid . Cid , error )
type Upgrade struct {
Height abi . ChainEpoch
2020-10-03 00:09:56 +00:00
Network network . Version
2020-10-01 22:02:40 +00:00
Migration UpgradeFunc
}
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 DefaultUpgradeSchedule ( ) UpgradeSchedule {
var us UpgradeSchedule
for _ , u := range [ ] Upgrade { {
Height : build . UpgradeBreezeHeight ,
Network : network . Version1 ,
Migration : UpgradeFaucetBurnRecovery ,
} , {
Height : build . UpgradeSmokeHeight ,
Network : network . Version2 ,
Migration : nil ,
} , {
Height : build . UpgradeIgnitionHeight ,
Network : network . Version3 ,
Migration : UpgradeIgnition ,
} , {
Height : build . UpgradeActorsV2Height ,
Network : network . Version4 ,
Migration : UpgradeActorsV2 ,
} , {
Height : build . UpgradeLiftoffHeight ,
Network : network . Version4 ,
Migration : UpgradeLiftoff ,
} } {
if u . Height < 0 {
// upgrade disabled
continue
}
us = append ( us , u )
}
return us
}
func ( us UpgradeSchedule ) Validate ( ) error {
// Make sure we're not trying to upgrade to version 0.
for _ , u := range us {
if u . Network <= 0 {
return xerrors . Errorf ( "cannot upgrade to version <= 0: %d" , u . Network )
}
}
// Make sure all the upgrades make sense.
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
2020-09-24 21:30:11 +00:00
func ( sm * StateManager ) handleStateForks ( ctx context . Context , root cid . Cid , height abi . ChainEpoch , cb ExecCallback , ts * types . TipSet ) ( cid . Cid , error ) {
retCid := root
var err error
2020-10-01 22:02:40 +00:00
f , ok := sm . stateMigrations [ height ]
2020-07-28 12:31:13 +00:00
if ok {
2020-09-24 21:30:11 +00:00
retCid , err = f ( ctx , sm , cb , root , ts )
2020-07-28 12:31:13 +00:00
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , err
2019-12-19 20:00:59 +00:00
}
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
2020-09-24 21:30:11 +00:00
func doTransfer ( cb ExecCallback , tree types . StateTree , from , to address . Address , amt abi . TokenAmount ) 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
fakeMsg := & types . Message {
From : from ,
To : to ,
Value : amt ,
Nonce : math . MaxUint64 ,
}
fakeRct := & types . MessageReceipt {
ExitCode : 0 ,
Return : nil ,
GasUsed : 0 ,
}
if err := cb ( fakeMsg . Cid ( ) , fakeMsg , & vm . ApplyRet {
MessageReceipt : * fakeRct ,
ActorErr : nil ,
ExecutionTrace : types . ExecutionTrace {
Msg : fakeMsg ,
MsgRct : fakeRct ,
Error : "" ,
Duration : 0 ,
GasCharges : nil ,
Subcalls : nil ,
} ,
Duration : 0 ,
GasCosts : vm . ZeroGasOutputs ( ) ,
} ) ; err != nil {
return xerrors . Errorf ( "recording transfer: %w" , err )
}
}
2020-09-05 03:01:36 +00:00
return nil
}
2020-09-24 21:30:11 +00:00
func UpgradeFaucetBurnRecovery ( ctx context . Context , sm * StateManager , cb ExecCallback , root cid . Cid , ts * types . TipSet ) ( cid . Cid , error ) {
2020-09-05 03:01:36 +00:00
// Some initial parameters
FundsForMiners := types . FromFil ( 1_000_000 )
LookbackEpoch := abi . ChainEpoch ( 32000 )
AccountCap := types . FromFil ( 0 )
BaseMinerBalance := types . FromFil ( 20 )
DesiredReimbursementBalance := types . FromFil ( 5_000_000 )
isSystemAccount := func ( addr address . Address ) ( bool , error ) {
id , err := address . IDFromAddress ( addr )
if err != nil {
return false , xerrors . Errorf ( "id address: %w" , err )
}
if id < 1000 {
return true , nil
}
return false , nil
}
minerFundsAlloc := func ( pow , tpow abi . StoragePower ) abi . TokenAmount {
return types . BigDiv ( types . BigMul ( pow , FundsForMiners ) , tpow )
}
// Grab lookback state for account checks
2020-09-08 20:45:44 +00:00
lbts , err := sm . ChainStore ( ) . GetTipsetByHeight ( ctx , LookbackEpoch , ts , false )
2020-09-05 03:01:36 +00:00
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to get tipset at lookback height: %w" , err )
2020-09-05 03:01:36 +00:00
}
2020-09-14 12:17:45 +00:00
lbtree , err := sm . ParentState ( lbts )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "loading state tree failed: %w" , err )
2020-09-05 03:01:36 +00:00
}
ReserveAddress , err := address . NewFromString ( "t090" )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to parse reserve address: %w" , err )
2020-09-05 03:01:36 +00:00
}
2020-09-24 21:30:11 +00:00
tree , err := sm . StateTree ( root )
if err != nil {
return cid . Undef , xerrors . Errorf ( "getting state tree: %w" , err )
2020-09-05 03:01:36 +00:00
}
type transfer struct {
From address . Address
To address . Address
Amt abi . TokenAmount
}
var transfers [ ] transfer
// Take all excess funds away, put them into the reserve account
2020-09-24 21:30:11 +00:00
err = tree . ForEach ( func ( addr address . Address , act * types . Actor ) error {
2020-09-05 03:01:36 +00:00
switch act . Code {
2020-09-22 19:02:29 +00:00
case builtin0 . AccountActorCodeID , builtin0 . MultisigActorCodeID , builtin0 . PaymentChannelActorCodeID :
2020-09-05 03:01:36 +00:00
sysAcc , err := isSystemAccount ( addr )
if err != nil {
return xerrors . Errorf ( "checking system account: %w" , err )
}
if ! sysAcc {
transfers = append ( transfers , transfer {
From : addr ,
To : ReserveAddress ,
Amt : act . Balance ,
} )
}
2020-09-22 19:02:29 +00:00
case builtin0 . StorageMinerActorCodeID :
2020-09-18 21:59:27 +00:00
var st miner0 . State
2020-09-14 12:17:45 +00:00
if err := sm . ChainStore ( ) . Store ( ctx ) . Get ( ctx , act . Head , & st ) ; err != nil {
2020-09-05 03:01:36 +00:00
return xerrors . Errorf ( "failed to load miner state: %w" , err )
}
var available abi . TokenAmount
{
defer func ( ) {
if err := recover ( ) ; err != nil {
log . Warnf ( "Get available balance failed (%s, %s, %s): %s" , addr , act . Head , act . Balance , err )
}
available = abi . NewTokenAmount ( 0 )
} ( )
// this panics if the miner doesnt have enough funds to cover their locked pledge
available = st . GetAvailableBalance ( act . Balance )
}
transfers = append ( transfers , transfer {
From : addr ,
To : ReserveAddress ,
Amt : available ,
} )
}
return nil
} )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "foreach over state tree failed: %w" , err )
2020-09-05 03:01:36 +00:00
}
// Execute transfers from previous step
for _ , t := range transfers {
2020-09-24 21:30:11 +00:00
if err := doTransfer ( cb , tree , t . From , t . To , t . Amt ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "transfer %s %s->%s failed: %w" , t . Amt , t . From , t . To , err )
2020-09-05 03:01:36 +00:00
}
}
// pull up power table to give miners back some funds proportional to their power
2020-09-18 21:59:27 +00:00
var ps power0 . State
2020-09-22 19:02:29 +00:00
powAct , err := tree . GetActor ( builtin0 . StoragePowerActorAddr )
2020-09-05 03:01:36 +00:00
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to load power actor: %w" , err )
2020-09-05 03:01:36 +00:00
}
cst := cbor . NewCborStore ( sm . ChainStore ( ) . Blockstore ( ) )
if err := cst . Get ( ctx , powAct . Head , & ps ) ; err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to get power actor state: %w" , err )
2020-09-05 03:01:36 +00:00
}
totalPower := ps . TotalBytesCommitted
var transfersBack [ ] transfer
// Now, we return some funds to places where they are needed
2020-09-24 21:30:11 +00:00
err = tree . ForEach ( func ( addr address . Address , act * types . Actor ) error {
2020-09-05 03:01:36 +00:00
lbact , err := lbtree . GetActor ( addr )
if err != nil {
if ! xerrors . Is ( err , types . ErrActorNotFound ) {
return xerrors . Errorf ( "failed to get actor in lookback state" )
}
}
prevBalance := abi . NewTokenAmount ( 0 )
if lbact != nil {
prevBalance = lbact . Balance
}
switch act . Code {
2020-09-22 19:02:29 +00:00
case builtin0 . AccountActorCodeID , builtin0 . MultisigActorCodeID , builtin0 . PaymentChannelActorCodeID :
2020-09-05 03:01:36 +00:00
nbalance := big . Min ( prevBalance , AccountCap )
if nbalance . Sign ( ) != 0 {
transfersBack = append ( transfersBack , transfer {
From : ReserveAddress ,
To : addr ,
Amt : nbalance ,
} )
}
2020-09-22 19:02:29 +00:00
case builtin0 . StorageMinerActorCodeID :
2020-09-18 21:59:27 +00:00
var st miner0 . State
2020-09-14 12:17:45 +00:00
if err := sm . ChainStore ( ) . Store ( ctx ) . Get ( ctx , act . Head , & st ) ; err != nil {
2020-09-05 03:01:36 +00:00
return xerrors . Errorf ( "failed to load miner state: %w" , err )
}
2020-09-18 21:59:27 +00:00
var minfo miner0 . MinerInfo
2020-09-05 03:01:36 +00:00
if err := cst . Get ( ctx , st . Info , & minfo ) ; err != nil {
return xerrors . Errorf ( "failed to get miner info: %w" , err )
}
2020-09-22 18:14:55 +00:00
sectorsArr , err := adt0 . AsArray ( sm . ChainStore ( ) . Store ( ctx ) , st . Sectors )
2020-09-05 03:01:36 +00:00
if err != nil {
return xerrors . Errorf ( "failed to load sectors array: %w" , err )
}
slen := sectorsArr . Length ( )
power := types . BigMul ( types . NewInt ( slen ) , types . NewInt ( uint64 ( minfo . SectorSize ) ) )
mfunds := minerFundsAlloc ( power , totalPower )
transfersBack = append ( transfersBack , transfer {
From : ReserveAddress ,
To : minfo . Worker ,
Amt : mfunds ,
} )
// Now make sure to give each miner who had power at the lookback some FIL
lbact , err := lbtree . GetActor ( addr )
if err == nil {
2020-09-18 21:59:27 +00:00
var lbst miner0 . State
2020-09-14 12:17:45 +00:00
if err := sm . ChainStore ( ) . Store ( ctx ) . Get ( ctx , lbact . Head , & lbst ) ; err != nil {
2020-09-05 03:01:36 +00:00
return xerrors . Errorf ( "failed to load miner state: %w" , err )
}
2020-09-22 18:14:55 +00:00
lbsectors , err := adt0 . AsArray ( sm . ChainStore ( ) . Store ( ctx ) , lbst . Sectors )
2020-09-05 03:01:36 +00:00
if err != nil {
return xerrors . Errorf ( "failed to load lb sectors array: %w" , err )
}
if lbsectors . Length ( ) > 0 {
transfersBack = append ( transfersBack , transfer {
From : ReserveAddress ,
To : minfo . Worker ,
Amt : BaseMinerBalance ,
} )
}
} else {
log . Warnf ( "failed to get miner in lookback state: %s" , err )
}
}
return nil
} )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "foreach over state tree failed: %w" , err )
2020-09-05 03:01:36 +00:00
}
for _ , t := range transfersBack {
2020-09-24 21:30:11 +00:00
if err := doTransfer ( cb , tree , t . From , t . To , t . Amt ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "transfer %s %s->%s failed: %w" , t . Amt , t . From , t . To , err )
2020-09-05 03:01:36 +00:00
}
}
// transfer all burnt funds back to the reserve account
2020-09-22 19:02:29 +00:00
burntAct , err := tree . GetActor ( builtin0 . BurntFundsActorAddr )
2020-09-05 03:01:36 +00:00
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to load burnt funds actor: %w" , err )
2020-09-05 03:01:36 +00:00
}
2020-09-24 21:30:11 +00:00
if err := doTransfer ( cb , tree , builtin0 . BurntFundsActorAddr , ReserveAddress , burntAct . Balance ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "failed to unburn funds: %w" , err )
2020-09-05 03:01:36 +00:00
}
// Top up the reimbursement service
reimbAddr , err := address . NewFromString ( "t0111" )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to parse reimbursement service address" )
2020-09-05 03:01:36 +00:00
}
reimb , err := tree . GetActor ( reimbAddr )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "failed to load reimbursement account actor: %w" , err )
2020-09-05 03:01:36 +00:00
}
difference := types . BigSub ( DesiredReimbursementBalance , reimb . Balance )
2020-09-24 21:30:11 +00:00
if err := doTransfer ( cb , tree , ReserveAddress , reimbAddr , difference ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "failed to top up reimbursement account: %w" , err )
2020-09-05 03:01:36 +00:00
}
// Now, a final sanity check to make sure the balances all check out
total := abi . NewTokenAmount ( 0 )
2020-09-24 21:30:11 +00:00
err = tree . ForEach ( func ( addr address . Address , act * types . Actor ) error {
2020-09-05 03:01:36 +00:00
total = types . BigAdd ( total , act . Balance )
return nil
} )
if err != nil {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "checking final state balance failed: %w" , err )
2020-09-05 03:01:36 +00:00
}
exp := types . FromFil ( build . FilBase )
if ! exp . Equals ( total ) {
2020-09-24 21:30:11 +00:00
return cid . Undef , xerrors . Errorf ( "resultant state tree account balance was not correct: %s" , total )
}
return tree . Flush ( ctx )
}
func UpgradeIgnition ( ctx context . Context , sm * StateManager , cb ExecCallback , root cid . Cid , ts * types . TipSet ) ( cid . Cid , error ) {
store := sm . cs . Store ( ctx )
2020-10-02 03:37:14 +00:00
epoch := ts . Height ( ) - 1
2020-10-05 17:35:21 +00:00
if build . UpgradeLiftoffHeight <= epoch {
return cid . Undef , xerrors . Errorf ( "liftoff height must be beyond ignition height" )
}
2020-10-02 03:37:14 +00:00
nst , err := nv3 . MigrateStateTree ( ctx , store , root , epoch )
2020-09-24 21:30:11 +00:00
if err != nil {
return cid . Undef , xerrors . Errorf ( "migrating actors state: %w" , err )
}
tree , err := sm . StateTree ( nst )
if err != nil {
return cid . Undef , xerrors . Errorf ( "getting state tree: %w" , err )
}
err = setNetworkName ( ctx , store , tree , "ignition" )
if err != nil {
return cid . Undef , xerrors . Errorf ( "setting network name: %w" , err )
}
split1 , err := address . NewFromString ( "t0115" )
if err != nil {
return cid . Undef , xerrors . Errorf ( "first split address: %w" , err )
}
split2 , err := address . NewFromString ( "t0116" )
if err != nil {
return cid . Undef , xerrors . Errorf ( "second split address: %w" , err )
}
2020-10-05 17:35:21 +00:00
err = resetGenesisMsigs ( ctx , sm , store , tree , build . UpgradeLiftoffHeight )
2020-09-24 21:30:11 +00:00
if err != nil {
return cid . Undef , xerrors . Errorf ( "resetting genesis msig start epochs: %w" , err )
}
err = splitGenesisMultisig ( ctx , cb , split1 , store , tree , 50 )
if err != nil {
return cid . Undef , xerrors . Errorf ( "splitting first msig: %w" , err )
}
err = splitGenesisMultisig ( ctx , cb , split2 , store , tree , 50 )
if err != nil {
return cid . Undef , xerrors . Errorf ( "splitting second msig: %w" , err )
}
2020-10-02 03:37:14 +00:00
err = nv3 . CheckStateTree ( ctx , store , nst , epoch , builtin0 . TotalFilecoin )
2020-09-24 21:30:11 +00:00
if err != nil {
return cid . Undef , xerrors . Errorf ( "sanity check after ignition upgrade failed: %w" , err )
}
return tree . Flush ( ctx )
}
2020-09-28 22:50:54 +00:00
func UpgradeActorsV2 ( ctx context . Context , sm * StateManager , cb ExecCallback , root cid . Cid , ts * types . TipSet ) ( cid . Cid , error ) {
store := sm . cs . Store ( ctx )
2020-10-02 03:37:14 +00:00
epoch := ts . Height ( ) - 1
2020-09-28 22:50:54 +00:00
info , err := store . Put ( ctx , new ( types . StateInfo ) )
if err != nil {
return cid . Undef , xerrors . Errorf ( "failed to create new state info for actors v2: %w" , err )
}
2020-10-02 03:37:14 +00:00
newHamtRoot , err := m2 . MigrateStateTree ( ctx , store , root , epoch , m2 . DefaultConfig ( ) )
2020-09-28 22:50:54 +00:00
if err != nil {
return cid . Undef , xerrors . Errorf ( "upgrading to actors v2: %w" , err )
}
2020-09-29 00:42:29 +00:00
newStateTree , err := states2 . LoadTree ( store , newHamtRoot )
if err != nil {
return cid . Undef , xerrors . Errorf ( "failed to load new state tree: %w" , err )
}
// Check all state-tree invariants.
if msgs , err := states2 . CheckStateInvariants ( newStateTree , types . TotalFilecoinInt ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "failed to check new state tree: %w" , err )
} else if ! msgs . IsEmpty ( ) {
// This error is going to be really nasty.
return cid . Undef , xerrors . Errorf ( "network upgrade failed: %v" , msgs . Messages ( ) )
}
2020-09-28 22:50:54 +00:00
newRoot , err := store . Put ( ctx , & types . StateRoot {
// TODO: ActorUpgrade: should be state-tree specific, not just the actors version.
Version : actors . Version2 ,
Actors : newHamtRoot ,
Info : info ,
} )
if err != nil {
return cid . Undef , xerrors . Errorf ( "failed to persist new state root: %w" , err )
}
2020-09-29 00:42:29 +00:00
// perform some basic sanity checks to make sure everything still works.
2020-09-28 22:50:54 +00:00
if newSm , err := state . LoadStateTree ( store , newRoot ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "state tree sanity load failed: %w" , err )
} else if newRoot2 , err := newSm . Flush ( ctx ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "state tree sanity flush failed: %w" , err )
} else if newRoot2 != newRoot {
return cid . Undef , xerrors . Errorf ( "state-root mismatch: %s != %s" , newRoot , newRoot2 )
} else if _ , err := newSm . GetActor ( builtin0 . InitActorAddr ) ; err != nil {
return cid . Undef , xerrors . Errorf ( "failed to load init actor after upgrade: %w" , err )
}
return newRoot , nil
}
2020-09-24 21:30:11 +00:00
func UpgradeLiftoff ( ctx context . Context , sm * StateManager , cb ExecCallback , root cid . Cid , ts * types . TipSet ) ( cid . Cid , error ) {
tree , err := sm . StateTree ( root )
if err != nil {
return cid . Undef , xerrors . Errorf ( "getting state tree: %w" , err )
}
err = setNetworkName ( ctx , sm . cs . Store ( ctx ) , tree , "mainnet" )
if err != nil {
return cid . Undef , xerrors . Errorf ( "setting network name: %w" , err )
}
return tree . Flush ( ctx )
}
2020-09-28 22:54:48 +00:00
func setNetworkName ( ctx context . Context , store adt . Store , tree * state . StateTree , name string ) error {
2020-09-24 21:30:11 +00:00
ia , err := tree . GetActor ( builtin0 . InitActorAddr )
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 )
}
if err := tree . SetActor ( builtin0 . InitActorAddr , ia ) ; err != nil {
return xerrors . Errorf ( "setting init actor: %w" , err )
}
return nil
}
func splitGenesisMultisig ( ctx context . Context , cb ExecCallback , addr address . Address , store adt0 . Store , tree * state . StateTree , portions uint64 ) error {
if portions < 1 {
return xerrors . Errorf ( "cannot split into 0 portions" )
}
mact , err := tree . GetActor ( addr )
if err != nil {
return xerrors . Errorf ( "getting msig actor: %w" , err )
}
mst , err := multisig . Load ( store , mact )
if err != nil {
return xerrors . Errorf ( "getting msig state: %w" , err )
}
signers , err := mst . Signers ( )
if err != nil {
return xerrors . Errorf ( "getting msig signers: %w" , err )
}
thresh , err := mst . Threshold ( )
if err != nil {
return xerrors . Errorf ( "getting msig threshold: %w" , err )
}
ibal , err := mst . InitialBalance ( )
if err != nil {
return xerrors . Errorf ( "getting msig initial balance: %w" , err )
}
se , err := mst . StartEpoch ( )
if err != nil {
return xerrors . Errorf ( "getting msig start epoch: %w" , err )
}
ud , err := mst . UnlockDuration ( )
if err != nil {
return xerrors . Errorf ( "getting msig unlock duration: %w" , err )
}
pending , err := adt0 . MakeEmptyMap ( store ) . Root ( )
if err != nil {
return xerrors . Errorf ( "failed to create empty map: %w" , err )
}
newIbal := big . Div ( ibal , types . NewInt ( portions ) )
newState := & multisig0 . State {
Signers : signers ,
NumApprovalsThreshold : thresh ,
NextTxnID : 0 ,
InitialBalance : newIbal ,
StartEpoch : se ,
UnlockDuration : ud ,
PendingTxns : pending ,
}
scid , err := store . Put ( ctx , newState )
if err != nil {
return xerrors . Errorf ( "storing new state: %w" , err )
}
newActor := types . Actor {
Code : builtin0 . MultisigActorCodeID ,
Head : scid ,
Nonce : 0 ,
Balance : big . Zero ( ) ,
}
i := uint64 ( 0 )
for i < portions {
keyAddr , err := makeKeyAddr ( addr , i )
if err != nil {
return xerrors . Errorf ( "creating key address: %w" , err )
}
idAddr , err := tree . RegisterNewAddress ( keyAddr )
if err != nil {
return xerrors . Errorf ( "registering new address: %w" , err )
}
err = tree . SetActor ( idAddr , & newActor )
if err != nil {
return xerrors . Errorf ( "setting new msig actor state: %w" , err )
}
if err := doTransfer ( cb , tree , addr , idAddr , newIbal ) ; err != nil {
return xerrors . Errorf ( "transferring split msig balance: %w" , err )
}
i ++
}
return nil
}
func makeKeyAddr ( splitAddr address . Address , count uint64 ) ( address . Address , error ) {
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
}
2020-10-05 17:35:21 +00:00
func resetGenesisMsigs ( ctx context . Context , sm * StateManager , store adt0 . Store , tree * state . StateTree , startEpoch abi . ChainEpoch ) error {
2020-09-24 21:30:11 +00:00
gb , err := sm . cs . GetGenesis ( )
if err != nil {
return xerrors . Errorf ( "getting genesis block: %w" , err )
}
gts , err := types . NewTipSet ( [ ] * types . BlockHeader { gb } )
if err != nil {
return xerrors . Errorf ( "getting genesis tipset: %w" , err )
}
cst := cbor . NewCborStore ( sm . cs . Blockstore ( ) )
genesisTree , err := state . LoadStateTree ( cst , gts . ParentState ( ) )
if err != nil {
return xerrors . Errorf ( "loading state tree: %w" , err )
}
err = genesisTree . ForEach ( func ( addr address . Address , genesisActor * types . Actor ) error {
if genesisActor . Code == builtin0 . MultisigActorCodeID {
currActor , err := tree . GetActor ( addr )
if err != nil {
return xerrors . Errorf ( "loading actor: %w" , err )
}
var currState multisig0 . State
if err := store . Get ( ctx , currActor . Head , & currState ) ; err != nil {
return xerrors . Errorf ( "reading multisig state: %w" , err )
}
2020-10-05 17:35:21 +00:00
currState . StartEpoch = startEpoch
2020-09-24 21:30:11 +00:00
currActor . Head , err = store . Put ( ctx , & currState )
if err != nil {
return xerrors . Errorf ( "writing new multisig state: %w" , err )
}
if err := tree . SetActor ( addr , currActor ) ; err != nil {
return xerrors . Errorf ( "setting multisig actor: %w" , err )
}
}
return nil
} )
if err != nil {
return xerrors . Errorf ( "iterating over genesis actors: %w" , err )
2020-09-05 03:01:36 +00:00
}
return nil
}