implement SlashConsensusFault
This commit is contained in:
parent
30564ba8b6
commit
fe020d9fd1
@ -17,4 +17,7 @@ const RandomnessLookback = 20
|
||||
const ProvingPeriodDuration = 2 * 60 // an hour, for now
|
||||
const PoSTChallangeTime = 1 * 60
|
||||
|
||||
const PowerCollateralProportion = 0.2
|
||||
const PerCapitaCollateralProportion = 0.05
|
||||
|
||||
// TODO: Move other important consts here
|
||||
|
@ -2,11 +2,14 @@ package actors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
@ -17,32 +20,35 @@ import (
|
||||
type StorageMarketActor struct{}
|
||||
|
||||
type smaMethods struct {
|
||||
Constructor uint64
|
||||
CreateStorageMiner uint64
|
||||
SlashConsensusFault uint64
|
||||
UpdateStorage uint64
|
||||
GetTotalStorage uint64
|
||||
PowerLookup uint64
|
||||
IsMiner uint64
|
||||
Constructor uint64
|
||||
CreateStorageMiner uint64
|
||||
SlashConsensusFault uint64
|
||||
UpdateStorage uint64
|
||||
GetTotalStorage uint64
|
||||
PowerLookup uint64
|
||||
IsMiner uint64
|
||||
PledgeCollateralForSize uint64
|
||||
}
|
||||
|
||||
var SMAMethods = smaMethods{1, 2, 3, 4, 5, 6, 7}
|
||||
var SMAMethods = smaMethods{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func (sma StorageMarketActor) Exports() []interface{} {
|
||||
return []interface{}{
|
||||
//1: sma.StorageMarketConstructor,
|
||||
2: sma.CreateStorageMiner,
|
||||
//3: sma.SlashConsensusFault,
|
||||
3: sma.SlashConsensusFault,
|
||||
4: sma.UpdateStorage,
|
||||
5: sma.GetTotalStorage,
|
||||
6: sma.PowerLookup,
|
||||
7: sma.IsMiner,
|
||||
//8: sma.StorageCollateralForSize,
|
||||
8: sma.PledgeCollateralForSize,
|
||||
}
|
||||
}
|
||||
|
||||
type StorageMarketState struct {
|
||||
Miners cid.Cid
|
||||
Miners cid.Cid
|
||||
MinerCount uint64
|
||||
|
||||
TotalStorage types.BigInt
|
||||
}
|
||||
|
||||
@ -89,6 +95,7 @@ func (sma StorageMarketActor) CreateStorageMiner(act *types.Actor, vmctx types.V
|
||||
return nil, err
|
||||
}
|
||||
self.Miners = ncid
|
||||
self.MinerCount++
|
||||
|
||||
nroot, err := vmctx.Storage().Put(&self)
|
||||
if err != nil {
|
||||
@ -109,6 +116,157 @@ func SupportedSectorSize(ssize types.BigInt) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type SlashConsensusFaultParams struct {
|
||||
Block1 *types.BlockHeader
|
||||
Block2 *types.BlockHeader
|
||||
}
|
||||
|
||||
func cidArrContains(a []cid.Cid, b cid.Cid) bool {
|
||||
for _, c := range a {
|
||||
if b == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func shouldSlash(block1, block2 *types.BlockHeader) bool {
|
||||
// First slashing condition, blocks have the same ticket round
|
||||
if block1.Height == block2.Height {
|
||||
return true
|
||||
}
|
||||
|
||||
/* Second slashing condition requires having access to the parent tipset blocks
|
||||
// This might not always be available, needs some thought on the best way to deal with this
|
||||
|
||||
|
||||
// Second slashing condition, miner ignored own block when mining
|
||||
// Case A: block2 could have been in block1's parent set but is not
|
||||
b1ParentHeight := block1.Height - len(block1.Tickets)
|
||||
|
||||
block1ParentTipSet := block1.Parents
|
||||
if !cidArrContains(block1.Parents, block2.Cid()) &&
|
||||
b1ParentHeight == block2.Height &&
|
||||
block1ParentTipSet.ParentCids == block2.ParentCids {
|
||||
return true
|
||||
}
|
||||
|
||||
// Case B: block1 could have been in block2's parent set but is not
|
||||
block2ParentTipSet := parentOf(block2)
|
||||
if !block2Parent.contains(block1) &&
|
||||
block2ParentTipSet.Height == block1.Height &&
|
||||
block2ParentTipSet.ParentCids == block1.ParentCids {
|
||||
return true
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *SlashConsensusFaultParams) ([]byte, ActorError) {
|
||||
if params.Block1.Miner != params.Block2.Miner {
|
||||
return nil, aerrors.New(2, "blocks must be from the same miner")
|
||||
}
|
||||
|
||||
rval, err := vmctx.Send(params.Block1.Miner, MAMethods.GetWorkerAddr, types.NewInt(0), nil)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "failed to get miner worker")
|
||||
}
|
||||
|
||||
worker, oerr := address.NewFromBytes(rval)
|
||||
if oerr != nil {
|
||||
// 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")
|
||||
}
|
||||
|
||||
if err := params.Block1.CheckBlockSignature(worker); err != nil {
|
||||
return nil, aerrors.Absorb(err, 3, "block1 did not have valid signature")
|
||||
}
|
||||
|
||||
if err := params.Block2.CheckBlockSignature(worker); err != nil {
|
||||
return nil, aerrors.Absorb(err, 4, "block2 did not have valid signature")
|
||||
}
|
||||
|
||||
// see the "Consensus Faults" section of the faults spec (faults.md)
|
||||
// for details on these slashing conditions.
|
||||
if !shouldSlash(params.Block1, params.Block2) {
|
||||
return nil, aerrors.New(5, "blocks do not prove a slashable offense")
|
||||
}
|
||||
|
||||
var self StorageMarketState
|
||||
old := vmctx.Storage().GetHead()
|
||||
if err := vmctx.Storage().Get(old, &self); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if types.BigCmp(self.TotalStorage, types.NewInt(0)) == 0 {
|
||||
return nil, aerrors.Fatal("invalid state, storage market actor has zero total storage")
|
||||
}
|
||||
|
||||
miner := params.Block1.Miner
|
||||
if has, err := MinerSetHas(context.TODO(), vmctx, self.Miners, miner); err != nil {
|
||||
return nil, aerrors.Wrapf(err, "failed to check miner in set")
|
||||
} else if !has {
|
||||
return nil, aerrors.New(6, "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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slashedCollateral := pledgeCollateralForSize(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 {
|
||||
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")
|
||||
}
|
||||
|
||||
// Remove the miner from the list of network miners
|
||||
ncid, err := MinerSetRemove(context.TODO(), vmctx, self.Miners, miner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
self.Miners = ncid
|
||||
self.MinerCount--
|
||||
|
||||
self.TotalStorage = types.BigSub(self.TotalStorage, minerPower)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type UpdateStorageParams struct {
|
||||
Delta types.BigInt
|
||||
}
|
||||
@ -162,21 +320,30 @@ func (sma StorageMarketActor) PowerLookup(act *types.Actor, vmctx types.VMContex
|
||||
return nil, aerrors.Wrap(err, "getting head")
|
||||
}
|
||||
|
||||
has, err := MinerSetHas(context.TODO(), vmctx, self.Miners, params.Miner)
|
||||
pow, err := powerLookup(context.TODO(), vmctx, &self, params.Miner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, aerrors.New(1, "miner not registered with storage market")
|
||||
}
|
||||
return pow.Bytes(), nil
|
||||
}
|
||||
|
||||
ret, err := vmctx.Send(params.Miner, MAMethods.GetPower, types.NewInt(0), nil)
|
||||
func powerLookup(ctx context.Context, vmctx types.VMContext, self *StorageMarketState, miner address.Address) (types.BigInt, ActorError) {
|
||||
has, err := MinerSetHas(context.TODO(), vmctx, self.Miners, miner)
|
||||
if err != nil {
|
||||
return nil, aerrors.Wrap(err, "invoke Miner.GetPower")
|
||||
return types.EmptyInt, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
if !has {
|
||||
return types.EmptyInt, aerrors.New(1, "miner not registered with storage market")
|
||||
}
|
||||
|
||||
ret, err := vmctx.Send(miner, MAMethods.GetPower, types.NewInt(0), nil)
|
||||
if err != nil {
|
||||
return types.EmptyInt, aerrors.Wrap(err, "invoke Miner.GetPower")
|
||||
}
|
||||
|
||||
return types.BigFromBytes(ret), nil
|
||||
}
|
||||
|
||||
type IsMinerParam struct {
|
||||
@ -197,6 +364,34 @@ func (sma StorageMarketActor) IsMiner(act *types.Actor, vmctx types.VMContext, p
|
||||
return cbg.EncodeBool(has), nil
|
||||
}
|
||||
|
||||
type PledgeCollateralParams struct {
|
||||
Size types.BigInt
|
||||
}
|
||||
|
||||
func (sma StorageMarketActor) PledgeCollateralForSize(act *types.Actor, vmctx types.VMContext, param *PledgeCollateralParams) ([]byte, ActorError) {
|
||||
var self StorageMarketState
|
||||
if err := vmctx.Storage().Get(vmctx.Storage().GetHead(), &self); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalCollateral := pledgeCollateralForSize(param.Size, self.TotalStorage, self.MinerCount)
|
||||
|
||||
return totalCollateral.Bytes(), nil
|
||||
}
|
||||
|
||||
func pledgeCollateralForSize(size, totalStorage types.BigInt, minerCount uint64) types.BigInt {
|
||||
|
||||
availableFilecoin := types.NewInt(5000000) // TODO: get actual available filecoin amount
|
||||
|
||||
totalPowerCollateral := types.BigDiv(types.BigMul(availableFilecoin, types.NewInt(uint64(float64(100*build.PowerCollateralProportion)))), types.NewInt(100))
|
||||
totalPerCapitaCollateral := types.BigDiv(types.BigMul(availableFilecoin, types.NewInt(uint64(float64(100*build.PowerCollateralProportion)))), types.NewInt(100))
|
||||
|
||||
powerCollateral := types.BigDiv(types.BigMul(totalPowerCollateral, size), totalStorage)
|
||||
perCapCollateral := types.BigDiv(totalPerCapitaCollateral, types.NewInt(minerCount))
|
||||
|
||||
return types.BigAdd(powerCollateral, perCapCollateral)
|
||||
}
|
||||
|
||||
func MinerSetHas(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (bool, aerrors.ActorError) {
|
||||
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
|
||||
if err != nil {
|
||||
@ -220,7 +415,17 @@ func MinerSetAdd(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to load miner set")
|
||||
}
|
||||
|
||||
if err := nd.Set(ctx, string(maddr.Bytes()), uint64(1)); err != nil {
|
||||
mkey := string(maddr.Bytes())
|
||||
err = nd.Find(ctx, mkey, nil)
|
||||
if err == nil {
|
||||
return cid.Undef, aerrors.Escalate(fmt.Errorf("miner already found"), "miner set add failed")
|
||||
}
|
||||
|
||||
if !xerrors.Is(err, hamt.ErrNotFound) {
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to do miner set check")
|
||||
}
|
||||
|
||||
if err := nd.Set(ctx, mkey, uint64(1)); err != nil {
|
||||
return cid.Undef, aerrors.Escalate(err, "adding miner address to set failed")
|
||||
}
|
||||
|
||||
@ -235,3 +440,30 @@ func MinerSetAdd(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func MinerSetRemove(ctx context.Context, vmctx types.VMContext, rcid cid.Cid, maddr address.Address) (cid.Cid, aerrors.ActorError) {
|
||||
nd, err := hamt.LoadNode(ctx, vmctx.Ipld(), rcid)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to load miner set")
|
||||
}
|
||||
|
||||
mkey := string(maddr.Bytes())
|
||||
switch nd.Delete(ctx, mkey) {
|
||||
case hamt.ErrNotFound:
|
||||
return cid.Undef, aerrors.New(1, "miner not found in set on delete")
|
||||
default:
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to delete miner from set")
|
||||
case nil:
|
||||
}
|
||||
|
||||
if err := nd.Flush(ctx); err != nil {
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to flush miner set")
|
||||
}
|
||||
|
||||
c, err := vmctx.Ipld().Put(ctx, nd)
|
||||
if err != nil {
|
||||
return cid.Undef, aerrors.Escalate(err, "failed to persist miner set to storage")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package actors_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
@ -8,12 +10,15 @@ import (
|
||||
. "github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
"github.com/filecoin-project/go-lotus/chain/wallet"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStorageMarketCreateMiner(t *testing.T) {
|
||||
func TestStorageMarketCreateAndSlashMiner(t *testing.T) {
|
||||
var ownerAddr, workerAddr address.Address
|
||||
|
||||
opts := []HarnessOpt{
|
||||
@ -72,4 +77,49 @@ func TestStorageMarketCreateMiner(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ownerAddr, oA, "return from GetOwner should be equal to the owner")
|
||||
}
|
||||
|
||||
{
|
||||
b1 := fakeBlock(t, minerAddr, 100)
|
||||
b2 := fakeBlock(t, minerAddr, 101)
|
||||
|
||||
signBlock(t, h.w, workerAddr, b1)
|
||||
signBlock(t, h.w, workerAddr, b2)
|
||||
|
||||
ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SMAMethods.SlashConsensusFault,
|
||||
&SlashConsensusFaultParams{
|
||||
Block1: b1,
|
||||
Block2: b2,
|
||||
})
|
||||
ApplyOK(t, ret)
|
||||
}
|
||||
}
|
||||
|
||||
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
|
||||
c := fakeCid(t, 1)
|
||||
return &types.BlockHeader{Height: 5, Miner: minerAddr, Timestamp: ts, StateRoot: c, Messages: c, MessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
|
||||
}
|
||||
|
||||
func fakeCid(t *testing.T, s int) cid.Cid {
|
||||
t.Helper()
|
||||
c, err := cid.NewPrefixV1(cid.Raw, mh.IDENTITY).Sum([]byte(fmt.Sprintf("%d", s)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func signBlock(t *testing.T, w *wallet.Wallet, worker address.Address, blk *types.BlockHeader) {
|
||||
t.Helper()
|
||||
sb, err := blk.SigningBytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sig, err := w.Sign(context.TODO(), worker, sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
blk.BlockSig = *sig
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ var PaymentChannelActorCodeCid cid.Cid
|
||||
var InitActorAddress = mustIDAddress(0)
|
||||
var NetworkAddress = mustIDAddress(1)
|
||||
var StorageMarketAddress = mustIDAddress(2)
|
||||
var BurntFundsAddress = mustIDAddress(99)
|
||||
|
||||
func mustIDAddress(i uint64) address.Address {
|
||||
a, err := address.NewIDAddress(i)
|
||||
|
@ -2375,7 +2375,7 @@ func (t *StorageMarketState) MarshalCBOR(w io.Writer) error {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{130}); err != nil {
|
||||
if _, err := w.Write([]byte{131}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -2385,6 +2385,11 @@ func (t *StorageMarketState) MarshalCBOR(w io.Writer) error {
|
||||
return xerrors.Errorf("failed to write cid field t.Miners: %w", err)
|
||||
}
|
||||
|
||||
// t.t.MinerCount (uint64)
|
||||
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.MinerCount)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.t.TotalStorage (types.BigInt)
|
||||
if err := t.TotalStorage.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
@ -2403,7 +2408,7 @@ func (t *StorageMarketState) UnmarshalCBOR(r io.Reader) error {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 2 {
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
@ -2419,6 +2424,16 @@ func (t *StorageMarketState) UnmarshalCBOR(r io.Reader) error {
|
||||
t.Miners = c
|
||||
|
||||
}
|
||||
// t.t.MinerCount (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.MinerCount = extra
|
||||
// t.t.TotalStorage (types.BigInt)
|
||||
|
||||
{
|
||||
@ -2648,3 +2663,127 @@ func (t *UpdateStorageParams) UnmarshalCBOR(r io.Reader) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *SlashConsensusFaultParams) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{130}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.t.Block1 (types.BlockHeader)
|
||||
if err := t.Block1.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.t.Block2 (types.BlockHeader)
|
||||
if err := t.Block2.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *SlashConsensusFaultParams) 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 != 2 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields (got %d)", extra)
|
||||
}
|
||||
|
||||
// t.t.Block1 (types.BlockHeader)
|
||||
|
||||
{
|
||||
|
||||
pb, err := br.PeekByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pb == cbg.CborNull[0] {
|
||||
var nbuf [1]byte
|
||||
if _, err := br.Read(nbuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
t.Block1 = new(types.BlockHeader)
|
||||
if err := t.Block1.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// t.t.Block2 (types.BlockHeader)
|
||||
|
||||
{
|
||||
|
||||
pb, err := br.PeekByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pb == cbg.CborNull[0] {
|
||||
var nbuf [1]byte
|
||||
if _, err := br.Read(nbuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
t.Block2 = new(types.BlockHeader)
|
||||
if err := t.Block2.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *PledgeCollateralParams) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte{129}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.t.Size (types.BigInt)
|
||||
if err := t.Size.MarshalCBOR(w); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *PledgeCollateralParams) 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 != 1 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.t.Size (types.BigInt)
|
||||
|
||||
{
|
||||
|
||||
if err := t.Size.UnmarshalCBOR(br); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -374,15 +374,6 @@ func (syncer *Syncer) validateTickets(ctx context.Context, mworker address.Addre
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkBlockSignature(blk *types.BlockHeader, worker address.Address) error {
|
||||
sigb, err := blk.SigningBytes()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get block signing bytes: %w", err)
|
||||
}
|
||||
|
||||
return blk.BlockSig.Verify(worker, sigb)
|
||||
}
|
||||
|
||||
// Should match up with 'Semantical Validation' in validation.md in the spec
|
||||
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
|
||||
h := b.Header
|
||||
@ -414,7 +405,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
|
||||
return xerrors.Errorf("GetMinerWorker failed: %w", err)
|
||||
}
|
||||
|
||||
if err := checkBlockSignature(h, waddr); err != nil {
|
||||
if err := h.CheckBlockSignature(waddr); err != nil {
|
||||
return xerrors.Errorf("check block signature failed: %w", err)
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,15 @@ func (blk *BlockHeader) SigningBytes() ([]byte, error) {
|
||||
return blkcopy.Serialize()
|
||||
}
|
||||
|
||||
func (blk *BlockHeader) CheckBlockSignature(worker address.Address) error {
|
||||
sigb, err := blk.SigningBytes()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get block signing bytes: %w", err)
|
||||
}
|
||||
|
||||
return blk.BlockSig.Verify(worker, sigb)
|
||||
}
|
||||
|
||||
type MsgMeta struct {
|
||||
BlsMessages cid.Cid
|
||||
SecpkMessages cid.Cid
|
||||
|
@ -1,11 +1,11 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-amt-ipld"
|
||||
amt "github.com/filecoin-project/go-amt-ipld"
|
||||
"github.com/filecoin-project/go-lotus/chain/actors/aerrors"
|
||||
"github.com/filecoin-project/go-lotus/chain/address"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-hamt-ipld"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
hamt "github.com/ipfs/go-hamt-ipld"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
@ -37,6 +37,7 @@ type VMContext interface {
|
||||
VerifySignature(sig *Signature, from address.Address, data []byte) aerrors.ActorError
|
||||
ChargeGas(uint64) aerrors.ActorError
|
||||
GetRandomness(height uint64) ([]byte, aerrors.ActorError)
|
||||
GetBalance(address.Address) (BigInt, aerrors.ActorError)
|
||||
}
|
||||
|
||||
type storageWrapper struct {
|
||||
|
@ -225,6 +225,19 @@ func ResolveToKeyAddr(state types.StateTree, cst *hamt.CborIpldStore, addr addre
|
||||
return aast.Address, nil
|
||||
}
|
||||
|
||||
func (vmctx *VMContext) GetBalance(a address.Address) (types.BigInt, aerrors.ActorError) {
|
||||
act, err := vmctx.state.GetActor(a)
|
||||
switch err {
|
||||
default:
|
||||
return types.EmptyInt, aerrors.Escalate(err, "failed to look up actor balance")
|
||||
case hamt.ErrNotFound:
|
||||
// REVIEW: should we just say 'account doesnt exist' == '0 balance'?
|
||||
return types.NewInt(0), nil
|
||||
case nil:
|
||||
return act.Balance, nil
|
||||
}
|
||||
}
|
||||
|
||||
type hBlocks interface {
|
||||
GetBlock(context.Context, cid.Cid) (block.Block, error)
|
||||
AddBlock(block.Block) error
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/chain/actors"
|
||||
"github.com/filecoin-project/go-lotus/chain/types"
|
||||
gen "github.com/whyrusleeping/cbor-gen"
|
||||
)
|
||||
|
||||
@ -72,6 +71,8 @@ func main() {
|
||||
actors.IsMinerParam{},
|
||||
actors.PowerLookupParams{},
|
||||
actors.UpdateStorageParams{},
|
||||
actors.SlashConsensusFaultParams{},
|
||||
actors.PledgeCollateralParams{},
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
Loading…
Reference in New Issue
Block a user