Skip to content

Commit 5791b4a

Browse files
committed
feat(shed): check command for FIP-0081 pledge calculation
lotus-shed audits fip0081-pledge
1 parent b0de2bd commit 5791b4a

File tree

2 files changed

+343
-4
lines changed

2 files changed

+343
-4
lines changed

cmd/lotus-shed/balances.go

+341-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ import (
2323
"github.com/filecoin-project/go-address"
2424
"github.com/filecoin-project/go-state-types/abi"
2525
"github.com/filecoin-project/go-state-types/big"
26-
26+
miner14 "github.com/filecoin-project/go-state-types/builtin/v14/miner"
27+
smoothing14 "github.com/filecoin-project/go-state-types/builtin/v14/util/smoothing"
28+
miner15 "github.com/filecoin-project/go-state-types/builtin/v15/miner"
29+
smoothing15 "github.com/filecoin-project/go-state-types/builtin/v15/util/smoothing"
30+
gststore "github.com/filecoin-project/go-state-types/store"
31+
32+
"github.com/filecoin-project/lotus/api"
33+
"github.com/filecoin-project/lotus/blockstore"
2734
"github.com/filecoin-project/lotus/build/buildconstants"
2835
"github.com/filecoin-project/lotus/chain/actors/adt"
2936
"github.com/filecoin-project/lotus/chain/actors/builtin"
@@ -69,6 +76,7 @@ var auditsCmd = &cli.Command{
6976
chainBalanceSanityCheckCmd,
7077
chainBalanceStateCmd,
7178
chainPledgeCmd,
79+
chainFip0081PledgeCmd,
7280
fillBalancesCmd,
7381
duplicatedMessagesCmd,
7482
},
@@ -941,3 +949,335 @@ var fillBalancesCmd = &cli.Command{
941949
return nil
942950
},
943951
}
952+
953+
var chainFip0081PledgeCmd = &cli.Command{
954+
Name: "fip0081-pledge",
955+
Description: "Calculate sector pledge values comparing current to pre-FIP-0081",
956+
ArgsUsage: "[epoch number]",
957+
Action: func(cctx *cli.Context) error {
958+
959+
ctx := lcli.ReqContext(cctx)
960+
961+
api, acloser, err := lcli.GetFullNodeAPIV1(cctx)
962+
if err != nil {
963+
return err
964+
}
965+
defer acloser()
966+
967+
var ts *types.TipSet
968+
if cctx.Args().Present() {
969+
epoch, err := strconv.ParseInt(cctx.Args().First(), 10, 64)
970+
if err != nil {
971+
return xerrors.Errorf("parsing epoch arg: %w", err)
972+
}
973+
ts, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(epoch), types.EmptyTSK)
974+
if err != nil {
975+
return err
976+
}
977+
} else {
978+
ts, err = api.ChainHead(ctx)
979+
if err != nil {
980+
return err
981+
}
982+
}
983+
984+
cases := []struct {
985+
sectorSize abi.SectorSize
986+
verifiedSize uint64
987+
duration abi.ChainEpoch
988+
}{
989+
{
990+
sectorSize: 2 << 10,
991+
verifiedSize: 2 << 10,
992+
duration: builtin.EpochsInYear,
993+
},
994+
{
995+
sectorSize: 2 << 10,
996+
verifiedSize: (2 << 10) / 2,
997+
duration: builtin.EpochsInYear,
998+
},
999+
{
1000+
sectorSize: 2 << 10,
1001+
verifiedSize: 0,
1002+
duration: builtin.EpochsInYear,
1003+
},
1004+
{
1005+
sectorSize: 2 << 10,
1006+
verifiedSize: 2 << 10,
1007+
duration: 3 * builtin.EpochsInYear,
1008+
},
1009+
{
1010+
sectorSize: 2 << 10,
1011+
verifiedSize: (2 << 10) / 2,
1012+
duration: 3 * builtin.EpochsInYear,
1013+
},
1014+
{
1015+
sectorSize: 2 << 10,
1016+
verifiedSize: 0,
1017+
duration: 3 * builtin.EpochsInYear,
1018+
},
1019+
{
1020+
sectorSize: 32 << 30,
1021+
verifiedSize: 32 << 30,
1022+
duration: builtin.EpochsInYear,
1023+
},
1024+
{
1025+
sectorSize: 32 << 30,
1026+
verifiedSize: (32 << 30) / 2,
1027+
duration: builtin.EpochsInYear,
1028+
},
1029+
{
1030+
sectorSize: 32 << 30,
1031+
verifiedSize: 0,
1032+
duration: builtin.EpochsInYear,
1033+
},
1034+
{
1035+
sectorSize: 32 << 30,
1036+
verifiedSize: 32 << 30,
1037+
duration: 3 * builtin.EpochsInYear,
1038+
},
1039+
{
1040+
sectorSize: 32 << 30,
1041+
verifiedSize: (32 << 30) / 2,
1042+
duration: 3 * builtin.EpochsInYear,
1043+
},
1044+
{
1045+
sectorSize: 32 << 30,
1046+
verifiedSize: 0,
1047+
duration: 3 * builtin.EpochsInYear,
1048+
},
1049+
{
1050+
sectorSize: 64 << 30,
1051+
verifiedSize: 64 << 30,
1052+
duration: builtin.EpochsInYear,
1053+
},
1054+
{
1055+
sectorSize: 64 << 30,
1056+
verifiedSize: (64 << 30) / 2,
1057+
duration: builtin.EpochsInYear,
1058+
},
1059+
{
1060+
sectorSize: 64 << 30,
1061+
verifiedSize: 0,
1062+
duration: builtin.EpochsInYear,
1063+
},
1064+
{
1065+
sectorSize: 64 << 30,
1066+
verifiedSize: 64 << 30,
1067+
duration: 3 * builtin.EpochsInYear,
1068+
},
1069+
{
1070+
sectorSize: 64 << 30,
1071+
verifiedSize: (64 << 30) / 2,
1072+
duration: 3 * builtin.EpochsInYear,
1073+
},
1074+
{
1075+
sectorSize: 64 << 30,
1076+
verifiedSize: 0,
1077+
duration: 3 * builtin.EpochsInYear,
1078+
},
1079+
}
1080+
1081+
fmt.Printf("\033[3mCalculating at epoch %d\033[0m\n", ts.Height())
1082+
fmt.Printf(" \033[1mSector Size\033[0m | \033[1mVerified %%\033[0m | \033[1mDuration\033[0m | \033[1mActual\033[0m | \033[1mPre-FIP-0081\033[0m | \033[1mDifference\033[0m\n")
1083+
fmt.Println(strings.Repeat("-", 119))
1084+
1085+
for _, c := range cases {
1086+
pledge, err := api.StateMinerInitialPledgeForSector(ctx, c.duration, c.sectorSize, c.verifiedSize, ts.Key())
1087+
if err != nil {
1088+
return err
1089+
}
1090+
newPledge, err := postFip0081StateMinerInitialPledgeForSector(ctx, api, c.duration, c.sectorSize, c.verifiedSize, ts)
1091+
if err != nil {
1092+
return err
1093+
}
1094+
if !pledge.Equals(newPledge) {
1095+
return xerrors.Errorf("failed to sanity check StateMinerInitialPledgeForSector calculation!")
1096+
}
1097+
oldPledge, err := preFip0081StateMinerInitialPledgeForSector(ctx, api, c.duration, c.sectorSize, c.verifiedSize, ts)
1098+
if err != nil {
1099+
return err
1100+
}
1101+
1102+
fmt.Printf(" %-11s | % 4.f%% | %0.f year(s) | %-24s | %-24s | %s\n",
1103+
c.sectorSize.ShortString(),
1104+
float64(c.verifiedSize)/float64(c.sectorSize)*100,
1105+
float64(c.duration)/builtin.EpochsInYear,
1106+
types.FIL(pledge).String(),
1107+
types.FIL(oldPledge).String(),
1108+
types.FIL(types.BigSub(pledge, oldPledge)).String(),
1109+
)
1110+
}
1111+
fmt.Println(strings.Repeat("-", 119))
1112+
1113+
return nil
1114+
},
1115+
}
1116+
1117+
// from itests/migration_test.go
1118+
1119+
// preFip0081StateMinerInitialPledgeForSector is the same calculation as StateMinerInitialPledgeForSector
1120+
// but uses miner14's version of the calculation without the FIP-0081 changes.
1121+
func preFip0081StateMinerInitialPledgeForSector(
1122+
ctx context.Context,
1123+
client api.FullNode,
1124+
sectorDuration abi.ChainEpoch,
1125+
sectorSize abi.SectorSize,
1126+
verifiedSize uint64,
1127+
ts *types.TipSet,
1128+
) (types.BigInt, error) {
1129+
bs := blockstore.NewAPIBlockstore(client)
1130+
ctxStore := gststore.WrapBlockStore(ctx, bs)
1131+
1132+
circSupply, err := client.StateVMCirculatingSupplyInternal(ctx, ts.Key())
1133+
if err != nil {
1134+
return types.NewInt(0), err
1135+
}
1136+
1137+
powerActor, err := client.StateGetActor(ctx, power.Address, ts.Key())
1138+
if err != nil {
1139+
return types.NewInt(0), err
1140+
}
1141+
1142+
powerState, err := power.Load(ctxStore, powerActor)
1143+
if err != nil {
1144+
return types.NewInt(0), err
1145+
}
1146+
1147+
rewardActor, err := client.StateGetActor(ctx, reward.Address, ts.Key())
1148+
if err != nil {
1149+
return types.NewInt(0), err
1150+
}
1151+
1152+
rewardState, err := reward.Load(ctxStore, rewardActor)
1153+
if err != nil {
1154+
return types.NewInt(0), err
1155+
}
1156+
1157+
networkQAPower, err := powerState.TotalPowerSmoothed()
1158+
if err != nil {
1159+
return types.NewInt(0), err
1160+
}
1161+
1162+
verifiedWeight := big.Mul(big.NewIntUnsigned(verifiedSize), big.NewInt(int64(sectorDuration)))
1163+
sectorWeight := builtin.QAPowerForWeight(sectorSize, sectorDuration, verifiedWeight)
1164+
1165+
thisEpochBaselinePower, err := rewardState.(interface {
1166+
ThisEpochBaselinePower() (abi.StoragePower, error)
1167+
}).ThisEpochBaselinePower()
1168+
if err != nil {
1169+
return types.NewInt(0), err
1170+
}
1171+
thisEpochRewardSmoothed, err := rewardState.(interface {
1172+
ThisEpochRewardSmoothed() (builtin.FilterEstimate, error)
1173+
}).ThisEpochRewardSmoothed()
1174+
if err != nil {
1175+
return types.NewInt(0), err
1176+
}
1177+
1178+
rewardEstimate := smoothing14.FilterEstimate{
1179+
PositionEstimate: thisEpochRewardSmoothed.PositionEstimate,
1180+
VelocityEstimate: thisEpochRewardSmoothed.VelocityEstimate,
1181+
}
1182+
networkQAPowerEstimate := smoothing14.FilterEstimate{
1183+
PositionEstimate: networkQAPower.PositionEstimate,
1184+
VelocityEstimate: networkQAPower.VelocityEstimate,
1185+
}
1186+
1187+
initialPledge := miner14.InitialPledgeForPower(
1188+
sectorWeight,
1189+
thisEpochBaselinePower,
1190+
rewardEstimate,
1191+
networkQAPowerEstimate,
1192+
circSupply.FilCirculating,
1193+
)
1194+
1195+
var initialPledgeNum = types.NewInt(110)
1196+
var initialPledgeDen = types.NewInt(100)
1197+
1198+
return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil
1199+
}
1200+
1201+
// postFip0081StateMinerInitialPledgeForSector should be the same calculation as StateMinerInitialPledgeForSector,
1202+
// it's here for sanity checking.
1203+
func postFip0081StateMinerInitialPledgeForSector(
1204+
ctx context.Context,
1205+
client api.FullNode,
1206+
sectorDuration abi.ChainEpoch,
1207+
sectorSize abi.SectorSize,
1208+
verifiedSize uint64,
1209+
ts *types.TipSet,
1210+
) (types.BigInt, error) {
1211+
bs := blockstore.NewAPIBlockstore(client)
1212+
ctxStore := gststore.WrapBlockStore(ctx, bs)
1213+
1214+
circSupply, err := client.StateVMCirculatingSupplyInternal(ctx, ts.Key())
1215+
if err != nil {
1216+
return types.NewInt(0), err
1217+
}
1218+
1219+
powerActor, err := client.StateGetActor(ctx, power.Address, ts.Key())
1220+
if err != nil {
1221+
return types.NewInt(0), err
1222+
}
1223+
1224+
powerState, err := power.Load(ctxStore, powerActor)
1225+
if err != nil {
1226+
return types.NewInt(0), err
1227+
}
1228+
1229+
rewardActor, err := client.StateGetActor(ctx, reward.Address, ts.Key())
1230+
if err != nil {
1231+
return types.NewInt(0), err
1232+
}
1233+
1234+
rewardState, err := reward.Load(ctxStore, rewardActor)
1235+
if err != nil {
1236+
return types.NewInt(0), err
1237+
}
1238+
1239+
networkQAPower, err := powerState.TotalPowerSmoothed()
1240+
if err != nil {
1241+
return types.NewInt(0), err
1242+
}
1243+
1244+
verifiedWeight := big.Mul(big.NewIntUnsigned(verifiedSize), big.NewInt(int64(sectorDuration)))
1245+
sectorWeight := builtin.QAPowerForWeight(sectorSize, sectorDuration, verifiedWeight)
1246+
1247+
thisEpochBaselinePower, err := rewardState.(interface {
1248+
ThisEpochBaselinePower() (abi.StoragePower, error)
1249+
}).ThisEpochBaselinePower()
1250+
if err != nil {
1251+
return types.NewInt(0), err
1252+
}
1253+
thisEpochRewardSmoothed, err := rewardState.(interface {
1254+
ThisEpochRewardSmoothed() (builtin.FilterEstimate, error)
1255+
}).ThisEpochRewardSmoothed()
1256+
if err != nil {
1257+
return types.NewInt(0), err
1258+
}
1259+
1260+
rewardEstimate := smoothing15.FilterEstimate{
1261+
PositionEstimate: thisEpochRewardSmoothed.PositionEstimate,
1262+
VelocityEstimate: thisEpochRewardSmoothed.VelocityEstimate,
1263+
}
1264+
networkQAPowerEstimate := smoothing15.FilterEstimate{
1265+
PositionEstimate: networkQAPower.PositionEstimate,
1266+
VelocityEstimate: networkQAPower.VelocityEstimate,
1267+
}
1268+
1269+
initialPledge := miner15.InitialPledgeForPower(
1270+
sectorWeight,
1271+
thisEpochBaselinePower,
1272+
rewardEstimate,
1273+
networkQAPowerEstimate,
1274+
circSupply.FilCirculating,
1275+
int64(ts.Height())-powerState.RampStartEpoch(),
1276+
powerState.RampDurationEpochs(),
1277+
)
1278+
1279+
var initialPledgeNum = types.NewInt(110)
1280+
var initialPledgeDen = types.NewInt(100)
1281+
1282+
return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil
1283+
}

itests/migration_test.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -1140,14 +1140,13 @@ func preFip0081StateMinerInitialPledgeForSector(ctx context.Context, t *testing.
11401140
VelocityEstimate: networkQAPower.VelocityEstimate,
11411141
}
11421142

1143-
initialPledge, err := miner14.InitialPledgeForPower(
1143+
initialPledge := miner14.InitialPledgeForPower(
11441144
sectorWeight,
11451145
thisEpochBaselinePower,
11461146
rewardEstimate,
11471147
networkQAPowerEstimate,
11481148
circSupply.FilCirculating,
1149-
), nil
1150-
req.NoError(err)
1149+
)
11511150

11521151
var initialPledgeNum = types.NewInt(110)
11531152
var initialPledgeDen = types.NewInt(100)

0 commit comments

Comments
 (0)