slash consensus fault needs to also be a method on the miner
This commit is contained in:
parent
fe020d9fd1
commit
197a2a3025
@ -17,7 +17,11 @@ const RandomnessLookback = 20
|
|||||||
const ProvingPeriodDuration = 2 * 60 // an hour, for now
|
const ProvingPeriodDuration = 2 * 60 // an hour, for now
|
||||||
const PoSTChallangeTime = 1 * 60
|
const PoSTChallangeTime = 1 * 60
|
||||||
|
|
||||||
const PowerCollateralProportion = 0.2
|
const PowerCollateralProportion = 20
|
||||||
const PerCapitaCollateralProportion = 0.05
|
const PerCapitaCollateralProportion = 5
|
||||||
|
const CollateralPrecision = 100
|
||||||
|
|
||||||
|
const TotalFilecoin = 2000000000
|
||||||
|
const FilecoinPrecision = 1000000000000000000
|
||||||
|
|
||||||
// TODO: Move other important consts here
|
// TODO: Move other important consts here
|
||||||
|
@ -3,6 +3,7 @@ package actors
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/build"
|
"github.com/filecoin-project/go-lotus/build"
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||||
@ -121,9 +122,10 @@ type maMethods struct {
|
|||||||
PaymentVerifyInclusion uint64
|
PaymentVerifyInclusion uint64
|
||||||
PaymentVerifySector uint64
|
PaymentVerifySector uint64
|
||||||
AddFaults uint64
|
AddFaults uint64
|
||||||
|
SlashConsensusFault uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
|
var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
|
||||||
|
|
||||||
func (sma StorageMinerActor) Exports() []interface{} {
|
func (sma StorageMinerActor) Exports() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
@ -146,6 +148,7 @@ func (sma StorageMinerActor) Exports() []interface{} {
|
|||||||
17: sma.PaymentVerifyInclusion,
|
17: sma.PaymentVerifyInclusion,
|
||||||
18: sma.PaymentVerifySector,
|
18: sma.PaymentVerifySector,
|
||||||
19: nil,
|
19: nil,
|
||||||
|
20: sma.SlashConsensusFault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,3 +705,57 @@ func (sma StorageMinerActor) PaymentVerifySector(act *types.Actor, vmctx types.V
|
|||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MinerSlashConsensusFault struct {
|
||||||
|
Slasher address.Address
|
||||||
|
AtHeight uint64
|
||||||
|
SlashedCollateral types.BigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sma StorageMinerActor) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) {
|
||||||
|
if vmctx.Message().From != StorageMarketAddress {
|
||||||
|
return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor")
|
||||||
|
}
|
||||||
|
|
||||||
|
slashedCollateral := params.SlashedCollateral
|
||||||
|
if types.BigCmp(slashedCollateral, act.Balance) < 0 {
|
||||||
|
slashedCollateral = act.Balance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some of the slashed collateral should be paid to the slasher
|
||||||
|
// GROWTH_RATE determines how fast the slasher share of slashed collateral will increase as block elapses
|
||||||
|
// current GROWTH_RATE results in SLASHER_SHARE reaches 1 after 30 blocks
|
||||||
|
// TODO: define arithmetic precision and rounding for this operation
|
||||||
|
blockElapsed := vmctx.BlockHeight() - params.AtHeight
|
||||||
|
growthRate := 1.26
|
||||||
|
initialShare := 0.001
|
||||||
|
|
||||||
|
// REVIEW: floating point precision loss anyone?
|
||||||
|
slasherPortion := initialShare * math.Pow(growthRate, float64(blockElapsed))
|
||||||
|
if slasherPortion > 1 {
|
||||||
|
slasherPortion = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const precision = 1000000
|
||||||
|
slasherShare := types.BigDiv(types.BigMul(types.NewInt(uint64(precision*slasherPortion)), slashedCollateral), types.NewInt(precision))
|
||||||
|
burnPortion := types.BigSub(slashedCollateral, slasherShare)
|
||||||
|
|
||||||
|
_, err := vmctx.Send(vmctx.Message().From, 0, slasherShare, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrap(err, "failed to pay slasher")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = vmctx.Send(BurntFundsAddress, 0, burnPortion, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, aerrors.Wrap(err, "failed to burn funds")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this still allows the miner to commit sectors and submit posts,
|
||||||
|
// their users could potentially be unaffected, but the miner will never be
|
||||||
|
// able to mine a block again
|
||||||
|
// One potential issue: the miner will have to pay back the slashed
|
||||||
|
// collateral to continue submitting PoSts, which includes pledge
|
||||||
|
// collateral that they no longer really 'need'
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -3,18 +3,17 @@ package actors
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/build"
|
"github.com/filecoin-project/go-lotus/build"
|
||||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
"github.com/filecoin-project/go-lotus/chain/types"
|
"github.com/filecoin-project/go-lotus/chain/types"
|
||||||
xerrors "golang.org/x/xerrors"
|
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
hamt "github.com/ipfs/go-hamt-ipld"
|
hamt "github.com/ipfs/go-hamt-ipld"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
xerrors "golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StorageMarketActor struct{}
|
type StorageMarketActor struct{}
|
||||||
@ -64,6 +63,21 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V
|
|||||||
return nil, aerrors.New(1, "Unsupported sector size")
|
return nil, aerrors.New(1, "Unsupported sector size")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var self StorageMarketState
|
||||||
|
old := vmctx.Storage().GetHead()
|
||||||
|
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reqColl, err := pledgeCollateralForSize(vmctx, types.NewInt(0), self.TotalStorage, self.MinerCount+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if types.BigCmp(vmctx.Message().Value, reqColl) < 0 {
|
||||||
|
return nil, aerrors.Newf(1, "not enough funds passed to cover required miner collateral (needed %s, got %s)", reqColl, vmctx.Message().Value)
|
||||||
|
}
|
||||||
|
|
||||||
encoded, err := CreateExecParams(StorageMinerCodeCid, &StorageMinerConstructorParams{
|
encoded, err := CreateExecParams(StorageMinerCodeCid, &StorageMinerConstructorParams{
|
||||||
Owner: params.Owner,
|
Owner: params.Owner,
|
||||||
Worker: params.Worker,
|
Worker: params.Worker,
|
||||||
@ -81,13 +95,7 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V
|
|||||||
|
|
||||||
naddr, nerr := address.NewFromBytes(ret)
|
naddr, nerr := address.NewFromBytes(ret)
|
||||||
if nerr != nil {
|
if nerr != nil {
|
||||||
return nil, aerrors.Absorb(nerr, 1, "could not read address of new actor")
|
return nil, aerrors.Absorb(nerr, 2, "could not read address of new actor")
|
||||||
}
|
|
||||||
|
|
||||||
var self StorageMarketState
|
|
||||||
old := vmctx.Storage().GetHead()
|
|
||||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ncid, err := MinerSetAdd(context.TODO(), vmctx, self.Miners, naddr)
|
ncid, err := MinerSetAdd(context.TODO(), vmctx, self.Miners, naddr)
|
||||||
@ -178,21 +186,21 @@ func (sma StorageMarketActor) SlashConsensusFault(act *types.Actor, vmctx types.
|
|||||||
worker, oerr := address.NewFromBytes(rval)
|
worker, oerr := address.NewFromBytes(rval)
|
||||||
if oerr != nil {
|
if oerr != nil {
|
||||||
// REVIEW: should this be fatal? i can't think of a real situation that would get us here
|
// REVIEW: should this be fatal? i can't think of a real situation that would get us here
|
||||||
return nil, aerrors.Escalate(oerr, "response from 'GetWorkerAddr' was not a valid address")
|
return nil, aerrors.Absorb(oerr, 3, "response from 'GetWorkerAddr' was not a valid address")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := params.Block1.CheckBlockSignature(worker); err != nil {
|
if err := params.Block1.CheckBlockSignature(worker); err != nil {
|
||||||
return nil, aerrors.Absorb(err, 3, "block1 did not have valid signature")
|
return nil, aerrors.Absorb(err, 4, "block1 did not have valid signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := params.Block2.CheckBlockSignature(worker); err != nil {
|
if err := params.Block2.CheckBlockSignature(worker); err != nil {
|
||||||
return nil, aerrors.Absorb(err, 4, "block2 did not have valid signature")
|
return nil, aerrors.Absorb(err, 5, "block2 did not have valid signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
// see the "Consensus Faults" section of the faults spec (faults.md)
|
// see the "Consensus Faults" section of the faults spec (faults.md)
|
||||||
// for details on these slashing conditions.
|
// for details on these slashing conditions.
|
||||||
if !shouldSlash(params.Block1, params.Block2) {
|
if !shouldSlash(params.Block1, params.Block2) {
|
||||||
return nil, aerrors.New(5, "blocks do not prove a slashable offense")
|
return nil, aerrors.New(6, "blocks do not prove a slashable offense")
|
||||||
}
|
}
|
||||||
|
|
||||||
var self StorageMarketState
|
var self StorageMarketState
|
||||||
@ -209,12 +217,7 @@ func (sma StorageMarketActor) SlashConsensusFault(act *types.Actor, vmctx types.
|
|||||||
if has, err := MinerSetHas(context.TODO(), vmctx, self.Miners, miner); err != nil {
|
if has, err := MinerSetHas(context.TODO(), vmctx, self.Miners, miner); err != nil {
|
||||||
return nil, aerrors.Wrapf(err, "failed to check miner in set")
|
return nil, aerrors.Wrapf(err, "failed to check miner in set")
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, aerrors.New(6, "either already slashed or not a miner")
|
return nil, aerrors.New(7, "either already slashed or not a miner")
|
||||||
}
|
|
||||||
|
|
||||||
minerBalance, err := vmctx.GetBalance(miner)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
minerPower, err := powerLookup(context.TODO(), vmctx, &self, miner)
|
minerPower, err := powerLookup(context.TODO(), vmctx, &self, miner)
|
||||||
@ -222,36 +225,23 @@ func (sma StorageMarketActor) SlashConsensusFault(act *types.Actor, vmctx types.
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
slashedCollateral := pledgeCollateralForSize(minerPower, self.TotalStorage, self.MinerCount)
|
slashedCollateral, err := pledgeCollateralForSize(vmctx, minerPower, self.TotalStorage, self.MinerCount)
|
||||||
if types.BigCmp(slashedCollateral, minerBalance) < 0 {
|
|
||||||
slashedCollateral = minerBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some of the slashed collateral should be paid to the slasher
|
|
||||||
// GROWTH_RATE determines how fast the slasher share of slashed collateral will increase as block elapses
|
|
||||||
// current GROWTH_RATE results in SLASHER_SHARE reaches 1 after 30 blocks
|
|
||||||
// TODO: define arithmetic precision and rounding for this operation
|
|
||||||
blockElapsed := vmctx.BlockHeight() - params.Block1.Height
|
|
||||||
growthRate := 1.26
|
|
||||||
initialShare := 0.001
|
|
||||||
|
|
||||||
// REVIEW: floating point precision loss anyone?
|
|
||||||
slasherPortion := initialShare * math.Pow(growthRate, float64(blockElapsed))
|
|
||||||
if slasherPortion > 1 {
|
|
||||||
slasherPortion = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
slasherShare := types.BigDiv(types.BigMul(types.NewInt(uint64(1000000*slasherPortion)), slashedCollateral), types.NewInt(1000000))
|
|
||||||
burnPortion := types.BigSub(slashedCollateral, slasherShare)
|
|
||||||
|
|
||||||
_, err = vmctx.Send(vmctx.Message().From, 0, slasherShare, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Wrap(err, "failed to pay slasher")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = vmctx.Send(BurntFundsAddress, 0, burnPortion, nil)
|
enc, err := SerializeParams(&MinerSlashConsensusFault{
|
||||||
|
Slasher: vmctx.Message().From,
|
||||||
|
AtHeight: params.Block1.Height,
|
||||||
|
SlashedCollateral: slashedCollateral,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, aerrors.Wrap(err, "failed to burn funds")
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = vmctx.Send(miner, MAMethods.SlashConsensusFault, types.NewInt(0), enc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the miner from the list of network miners
|
// Remove the miner from the list of network miners
|
||||||
@ -264,6 +254,15 @@ func (sma StorageMarketActor) SlashConsensusFault(act *types.Actor, vmctx types.
|
|||||||
|
|
||||||
self.TotalStorage = types.BigSub(self.TotalStorage, minerPower)
|
self.TotalStorage = types.BigSub(self.TotalStorage, minerPower)
|
||||||
|
|
||||||
|
nroot, err := vmctx.Storage().Put(&self)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := vmctx.Storage().Commit(old, nroot); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,22 +373,59 @@ func (sma StorageMarketActor) PledgeCollateralForSize(act *types.Actor, vmctx ty
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
totalCollateral := pledgeCollateralForSize(param.Size, self.TotalStorage, self.MinerCount)
|
totalCollateral, err := pledgeCollateralForSize(vmctx, param.Size, self.TotalStorage, self.MinerCount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return totalCollateral.Bytes(), nil
|
return totalCollateral.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pledgeCollateralForSize(size, totalStorage types.BigInt, minerCount uint64) types.BigInt {
|
func pledgeCollateralForSize(vmctx types.VMContext, size, totalStorage types.BigInt, minerCount uint64) (types.BigInt, aerrors.ActorError) {
|
||||||
|
netBalance, err := vmctx.GetBalance(NetworkAddress)
|
||||||
|
if err != nil {
|
||||||
|
return types.EmptyInt, err
|
||||||
|
}
|
||||||
|
|
||||||
availableFilecoin := types.NewInt(5000000) // TODO: get actual available filecoin amount
|
// TODO: the spec says to also grab 'total vested filecoin' and include it as available
|
||||||
|
// If we don't factor that in, we effectively assume all of the locked up filecoin is 'available'
|
||||||
|
// the blocker on that right now is that its hard to tell how much filecoin is unlocked
|
||||||
|
|
||||||
totalPowerCollateral := types.BigDiv(types.BigMul(availableFilecoin, types.NewInt(uint64(float64(100*build.PowerCollateralProportion)))), types.NewInt(100))
|
availableFilecoin := types.BigSub(
|
||||||
totalPerCapitaCollateral := types.BigDiv(types.BigMul(availableFilecoin, types.NewInt(uint64(float64(100*build.PowerCollateralProportion)))), types.NewInt(100))
|
types.BigMul(types.NewInt(build.TotalFilecoin), types.NewInt(build.FilecoinPrecision)),
|
||||||
|
netBalance,
|
||||||
|
)
|
||||||
|
|
||||||
powerCollateral := types.BigDiv(types.BigMul(totalPowerCollateral, size), totalStorage)
|
totalPowerCollateral := types.BigDiv(
|
||||||
perCapCollateral := types.BigDiv(totalPerCapitaCollateral, types.NewInt(minerCount))
|
types.BigMul(
|
||||||
|
availableFilecoin,
|
||||||
|
types.NewInt(build.PowerCollateralProportion),
|
||||||
|
),
|
||||||
|
types.NewInt(build.CollateralPrecision),
|
||||||
|
)
|
||||||
|
|
||||||
return types.BigAdd(powerCollateral, perCapCollateral)
|
totalPerCapitaCollateral := types.BigDiv(
|
||||||
|
types.BigMul(
|
||||||
|
availableFilecoin,
|
||||||
|
types.NewInt(build.PerCapitaCollateralProportion),
|
||||||
|
),
|
||||||
|
types.NewInt(build.CollateralPrecision),
|
||||||
|
)
|
||||||
|
|
||||||
|
powerCollateral := types.BigDiv(
|
||||||
|
types.BigMul(
|
||||||
|
totalPowerCollateral,
|
||||||
|
size,
|
||||||
|
),
|
||||||
|
totalStorage,
|
||||||
|
)
|
||||||
|
|
||||||
|
perCapCollateral := types.BigDiv(
|
||||||
|
totalPerCapitaCollateral,
|
||||||
|
types.NewInt(minerCount),
|
||||||
|
)
|
||||||
|
|
||||||
|
return types.BigAdd(powerCollateral, perCapCollateral), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MinerSetHas(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (bool, aerrors.ActorError) {
|
func MinerSetHas(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (bool, aerrors.ActorError) {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/build"
|
"github.com/filecoin-project/go-lotus/build"
|
||||||
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
|
|
||||||
. "github.com/filecoin-project/go-lotus/chain/actors"
|
. "github.com/filecoin-project/go-lotus/chain/actors"
|
||||||
"github.com/filecoin-project/go-lotus/chain/address"
|
"github.com/filecoin-project/go-lotus/chain/address"
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-lotus/chain/wallet"
|
"github.com/filecoin-project/go-lotus/chain/wallet"
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
cid "github.com/ipfs/go-cid"
|
||||||
|
hamt "github.com/ipfs/go-hamt-ipld"
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
mh "github.com/multiformats/go-multihash"
|
mh "github.com/multiformats/go-multihash"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -22,7 +24,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
var ownerAddr, workerAddr address.Address
|
var ownerAddr, workerAddr address.Address
|
||||||
|
|
||||||
opts := []HarnessOpt{
|
opts := []HarnessOpt{
|
||||||
HarnessAddr(&ownerAddr, 100000),
|
HarnessAddr(&ownerAddr, 1000000),
|
||||||
HarnessAddr(&workerAddr, 100000),
|
HarnessAddr(&workerAddr, 100000),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +32,11 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
|
|
||||||
var minerAddr address.Address
|
var minerAddr address.Address
|
||||||
{
|
{
|
||||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SMAMethods.CreateStorageMiner,
|
// cheating the bootstrapping problem
|
||||||
|
cheatStorageMarketTotal(t, h)
|
||||||
|
|
||||||
|
ret, _ := h.InvokeWithValue(t, ownerAddr, StorageMarketAddress, SMAMethods.CreateStorageMiner,
|
||||||
|
types.NewInt(500000),
|
||||||
&CreateStorageMinerParams{
|
&CreateStorageMinerParams{
|
||||||
Owner: ownerAddr,
|
Owner: ownerAddr,
|
||||||
Worker: workerAddr,
|
Worker: workerAddr,
|
||||||
@ -92,6 +98,47 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
|||||||
})
|
})
|
||||||
ApplyOK(t, ret)
|
ApplyOK(t, ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SMAMethods.PowerLookup,
|
||||||
|
&PowerLookupParams{Miner: minerAddr})
|
||||||
|
assert.Equal(t, ret.ExitCode, byte(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SMAMethods.IsMiner, &IsMinerParam{minerAddr})
|
||||||
|
ApplyOK(t, ret)
|
||||||
|
assert.Equal(t, ret.Return, cbg.CborBoolFalse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cheatStorageMarketTotal(t *testing.T, h *Harness) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
sma, err := h.vm.StateTree().GetActor(StorageMarketAddress)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cst := hamt.CSTFromBstore(h.cs.Blockstore())
|
||||||
|
|
||||||
|
var smastate StorageMarketState
|
||||||
|
if err := cst.Get(context.TODO(), sma.Head, &smastate); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
smastate.TotalStorage = types.NewInt(10000)
|
||||||
|
|
||||||
|
c, err := cst.Put(context.TODO(), &smastate)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sma.Head = c
|
||||||
|
|
||||||
|
if err := h.vm.StateTree().SetActor(StorageMarketAddress, sma); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
|
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
|
||||||
|
@ -47,6 +47,22 @@ func Newf(retCode uint8, format string, args ...interface{}) ActorError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Fatal(message string, args ...interface{}) ActorError {
|
||||||
|
return &actorError{
|
||||||
|
fatal: true,
|
||||||
|
msg: message,
|
||||||
|
frame: xerrors.Caller(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatalf(format string, args ...interface{}) ActorError {
|
||||||
|
return &actorError{
|
||||||
|
fatal: true,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
frame: xerrors.Caller(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wrap extens chain of errors with a message
|
// Wrap extens chain of errors with a message
|
||||||
func Wrap(err ActorError, message string) ActorError {
|
func Wrap(err ActorError, message string) ActorError {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -2697,7 +2697,7 @@ func (t *SlashConsensusFaultParams) UnmarshalCBOR(r io.Reader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if extra != 2 {
|
if extra != 2 {
|
||||||
return fmt.Errorf("cbor input had wrong number of fields (got %d)", extra)
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.t.Block1 (types.BlockHeader)
|
// t.t.Block1 (types.BlockHeader)
|
||||||
@ -2787,3 +2787,75 @@ func (t *PledgeCollateralParams) UnmarshalCBOR(r io.Reader) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *MinerSlashConsensusFault) MarshalCBOR(w io.Writer) error {
|
||||||
|
if t == nil {
|
||||||
|
_, err := w.Write(cbg.CborNull)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.Write([]byte{131}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Slasher (address.Address)
|
||||||
|
if err := t.Slasher.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.AtHeight (uint64)
|
||||||
|
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.AtHeight)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.SlashedCollateral (types.BigInt)
|
||||||
|
if err := t.SlashedCollateral.MarshalCBOR(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *MinerSlashConsensusFault) UnmarshalCBOR(r io.Reader) error {
|
||||||
|
br := cbg.GetPeeker(r)
|
||||||
|
|
||||||
|
maj, extra, err := cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajArray {
|
||||||
|
return fmt.Errorf("cbor input should be of type array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extra != 3 {
|
||||||
|
return fmt.Errorf("cbor input had wrong number of fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// t.t.Slasher (address.Address)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.Slasher.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// t.t.AtHeight (uint64)
|
||||||
|
|
||||||
|
maj, extra, err = cbg.CborReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if maj != cbg.MajUnsignedInt {
|
||||||
|
return fmt.Errorf("wrong type for uint64 field")
|
||||||
|
}
|
||||||
|
t.AtHeight = extra
|
||||||
|
// t.t.SlashedCollateral (types.BigInt)
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
if err := t.SlashedCollateral.UnmarshalCBOR(br); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -240,11 +240,17 @@ func (h *Harness) SendFunds(t testing.TB, from address.Address, to address.Addre
|
|||||||
func (h *Harness) Invoke(t testing.TB, from address.Address, to address.Address,
|
func (h *Harness) Invoke(t testing.TB, from address.Address, to address.Address,
|
||||||
method uint64, params cbg.CBORMarshaler) (*vm.ApplyRet, *state.StateTree) {
|
method uint64, params cbg.CBORMarshaler) (*vm.ApplyRet, *state.StateTree) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
return h.InvokeWithValue(t, from, to, method, types.NewInt(0), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Harness) InvokeWithValue(t testing.TB, from address.Address, to address.Address,
|
||||||
|
method uint64, value types.BigInt, params cbg.CBORMarshaler) (*vm.ApplyRet, *state.StateTree) {
|
||||||
|
t.Helper()
|
||||||
return h.Apply(t, types.Message{
|
return h.Apply(t, types.Message{
|
||||||
To: to,
|
To: to,
|
||||||
From: from,
|
From: from,
|
||||||
Method: method,
|
Method: method,
|
||||||
Value: types.NewInt(0),
|
Value: value,
|
||||||
Params: DumpObject(t, params),
|
Params: DumpObject(t, params),
|
||||||
GasPrice: types.NewInt(1),
|
GasPrice: types.NewInt(1),
|
||||||
GasLimit: types.NewInt(testGasLimit),
|
GasLimit: types.NewInt(testGasLimit),
|
||||||
|
@ -98,15 +98,29 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types
|
|||||||
return nil, xerrors.Errorf("set storage market actor: %w", err)
|
return nil, xerrors.Errorf("set storage market actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netAmt := types.Fil(types.NewInt(build.TotalFilecoin))
|
||||||
|
for _, amt := range actmap {
|
||||||
|
netAmt = types.BigSub(netAmt, amt)
|
||||||
|
}
|
||||||
|
|
||||||
err = state.SetActor(actors.NetworkAddress, &types.Actor{
|
err = state.SetActor(actors.NetworkAddress, &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountActorCodeCid,
|
||||||
Balance: types.NewInt(100000000000),
|
Balance: netAmt,
|
||||||
Head: emptyobject,
|
Head: emptyobject,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("set network account actor: %w", err)
|
return nil, xerrors.Errorf("set network account actor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = state.SetActor(actors.BurntFundsAddress, &types.Actor{
|
||||||
|
Code: actors.AccountActorCodeCid,
|
||||||
|
Balance: types.NewInt(0),
|
||||||
|
Head: emptyobject,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("set burnt funds account actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
for a, v := range actmap {
|
for a, v := range actmap {
|
||||||
err = state.SetActor(a, &types.Actor{
|
err = state.SetActor(a, &types.Actor{
|
||||||
Code: actors.AccountActorCodeCid,
|
Code: actors.AccountActorCodeCid,
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-lotus/build"
|
||||||
|
|
||||||
cbor "github.com/ipfs/go-ipld-cbor"
|
cbor "github.com/ipfs/go-ipld-cbor"
|
||||||
"github.com/polydawn/refmt/obj/atlas"
|
"github.com/polydawn/refmt/obj/atlas"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
@ -41,6 +43,10 @@ func NewInt(i uint64) BigInt {
|
|||||||
return BigInt{big.NewInt(0).SetUint64(i)}
|
return BigInt{big.NewInt(0).SetUint64(i)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Fil(i BigInt) BigInt {
|
||||||
|
return BigMul(i, NewInt(build.FilecoinPrecision))
|
||||||
|
}
|
||||||
|
|
||||||
func BigFromBytes(b []byte) BigInt {
|
func BigFromBytes(b []byte) BigInt {
|
||||||
i := big.NewInt(0).SetBytes(b)
|
i := big.NewInt(0).SetBytes(b)
|
||||||
return BigInt{i}
|
return BigInt{i}
|
||||||
|
@ -73,6 +73,7 @@ func main() {
|
|||||||
actors.UpdateStorageParams{},
|
actors.UpdateStorageParams{},
|
||||||
actors.SlashConsensusFaultParams{},
|
actors.SlashConsensusFaultParams{},
|
||||||
actors.PledgeCollateralParams{},
|
actors.PledgeCollateralParams{},
|
||||||
|
actors.MinerSlashConsensusFault{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user