Merge pull request #182 from filecoin-project/feat/mining-refactor

Mining refactor and correct election proofs
This commit is contained in:
Whyrusleeping 2019-09-10 16:14:53 +10:00 committed by GitHub
commit 450ce5df07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1091 additions and 621 deletions

View File

@ -48,16 +48,11 @@ type FullNode interface {
ChainNotify(context.Context) (<-chan *store.HeadChange, error)
ChainHead(context.Context) (*types.TipSet, error) // TODO: check serialization
ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error // TODO: check serialization
ChainGetRandomness(context.Context, *types.TipSet) ([]byte, error)
ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error)
ChainWaitMsg(context.Context, cid.Cid) (*MsgWait, error)
ChainGetBlock(context.Context, cid.Cid) (*types.BlockHeader, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*BlockMessages, error)
ChainGetBlockReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error)
ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
// if tipset is nil, we'll use heaviest
ChainCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
// messages
@ -106,6 +101,11 @@ type FullNode interface {
StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error)
StateMinerProvingSet(context.Context, address.Address) ([]*SectorInfo, error)
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
// if tipset is nil, we'll use heaviest
StateCall(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error)
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error)
PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error)
PaychList(context.Context) ([]address.Address, error)

View File

@ -39,17 +39,14 @@ type FullNodeStruct struct {
CommonStruct
Internal struct {
ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"`
ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error `perm:"write"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, *types.TipSet) ([]byte, error) `perm:"read"`
ChainWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetBlockReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
ChainCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
ChainGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
ChainReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
ChainNotify func(context.Context) (<-chan *store.HeadChange, error) `perm:"read"`
ChainSubmitBlock func(ctx context.Context, blk *chain.BlockMsg) error `perm:"write"`
ChainHead func(context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetRandomness func(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error) `perm:"read"`
ChainWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"`
ChainGetBlock func(context.Context, cid.Cid) (*types.BlockHeader, error) `perm:"read"`
ChainGetBlockMessages func(context.Context, cid.Cid) (*BlockMessages, error) `perm:"read"`
ChainGetBlockReceipts func(context.Context, cid.Cid) ([]*types.MessageReceipt, error) `perm:"read"`
MpoolPending func(context.Context, *types.TipSet) ([]*types.SignedMessage, error) `perm:"read"`
MpoolPush func(context.Context, *types.SignedMessage) error `perm:"write"`
@ -75,9 +72,13 @@ type FullNodeStruct struct {
ClientStartDeal func(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) `perm:"admin"`
ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"`
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
StateMinerProvingSet func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"`
StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"`
PaychCreate func(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) `perm:"sign"`
PaychList func(context.Context) ([]address.Address, error) `perm:"read"`
@ -203,26 +204,14 @@ func (c *FullNodeStruct) ChainHead(ctx context.Context) (*types.TipSet, error) {
return c.Internal.ChainHead(ctx)
}
func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts *types.TipSet) ([]byte, error) {
return c.Internal.ChainGetRandomness(ctx, pts)
func (c *FullNodeStruct) ChainGetRandomness(ctx context.Context, pts *types.TipSet, ticks []*types.Ticket, lb int) ([]byte, error) {
return c.Internal.ChainGetRandomness(ctx, pts, ticks, lb)
}
func (c *FullNodeStruct) ChainWaitMsg(ctx context.Context, msgc cid.Cid) (*MsgWait, error) {
return c.Internal.ChainWaitMsg(ctx, msgc)
}
func (c *FullNodeStruct) ChainCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
return c.Internal.ChainCall(ctx, msg, ts)
}
func (c *FullNodeStruct) ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
return c.Internal.ChainGetActor(ctx, actor, ts)
}
func (c *FullNodeStruct) ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) {
return c.Internal.ChainReadState(ctx, act, ts)
}
func (c *FullNodeStruct) WalletNew(ctx context.Context, typ string) (address.Address, error) {
return c.Internal.WalletNew(ctx, typ)
}
@ -283,6 +272,22 @@ func (c *FullNodeStruct) StateMinerPower(ctx context.Context, a address.Address,
return c.Internal.StateMinerPower(ctx, a, ts)
}
func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
return c.Internal.StateMinerWorker(ctx, m, ts)
}
func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
return c.Internal.StateCall(ctx, msg, ts)
}
func (c *FullNodeStruct) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
return c.Internal.StateGetActor(ctx, actor, ts)
}
func (c *FullNodeStruct) StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) {
return c.Internal.StateReadState(ctx, act, ts)
}
func (c *FullNodeStruct) PaychCreate(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, error) {
return c.Internal.PaychCreate(ctx, from, to, amt)
}

View File

@ -12,5 +12,6 @@ const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours
const DealVoucherSkewLimit = 10
const ForkLengthThreshold = 20
const RandomnessLookback = 20
// TODO: Move other important consts here

View File

@ -245,8 +245,10 @@ func (bs *BlockSync) processStatus(req *BlockSyncRequest, res *BlockSyncResponse
panic("not handled")
case 203: // Internal Error
return fmt.Errorf("block sync peer errored: %s", res.Message)
case 204:
return fmt.Errorf("block sync request invalid: %s", res.Message)
default:
return fmt.Errorf("unrecognized response code")
return fmt.Errorf("unrecognized response code: %d", res.Status)
}
}
@ -261,10 +263,11 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tipset []cid.Cid, count int)
Options: BSOptBlocks,
}
var err error
var oerr error
for _, p := range perm {
res, err := bs.sendRequestToPeer(ctx, peers[p], req)
if err != nil {
oerr = err
log.Warnf("BlockSync request failed for peer %s: %s", peers[p].String(), err)
continue
}
@ -272,12 +275,12 @@ func (bs *BlockSync) GetBlocks(ctx context.Context, tipset []cid.Cid, count int)
if res.Status == 0 {
return bs.processBlocksResponse(req, res)
}
err = bs.processStatus(req, res)
if err != nil {
oerr = bs.processStatus(req, res)
if oerr != nil {
log.Warnf("BlockSync peer %s response was an error: %s", peers[p].String(), err)
}
}
return nil, xerrors.Errorf("GetBlocks failed with all peers: %w", err)
return nil, xerrors.Errorf("GetBlocks failed with all peers: %w", oerr)
}
func (bs *BlockSync) GetFullTipSet(ctx context.Context, p peer.ID, h []cid.Cid) (*store.FullTipSet, error) {
@ -396,7 +399,7 @@ func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSync
return nil, err
}
if !cidArrsEqual(cur.Parents(), nts.Cids()) {
if !types.CidArrsEqual(cur.Parents(), nts.Cids()) {
return nil, fmt.Errorf("parents of tipset[%d] were not tipset[%d]", bi-1, bi)
}
@ -406,18 +409,6 @@ func (bs *BlockSync) processBlocksResponse(req *BlockSyncRequest, res *BlockSync
return out, nil
}
func cidArrsEqual(a, b []cid.Cid) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if b[i] != v {
return false
}
}
return true
}
func (bs *BlockSync) GetBlock(ctx context.Context, c cid.Cid) (*types.BlockHeader, error) {
sb, err := bs.bserv.GetBlock(ctx, c)
if err != nil {

View File

@ -77,7 +77,7 @@ func (h *Handler) sendSignedResponse(resp StorageDealResponse) error {
From: h.actor,
Method: actors.MAMethods.GetWorkerAddr,
}
r, err := h.full.ChainCall(context.TODO(), getworker, nil)
r, err := h.full.StateCall(context.TODO(), getworker, nil)
if err != nil {
return xerrors.Errorf("getting worker address: %w", err)
}

View File

@ -3,16 +3,20 @@ package gen
import (
"bytes"
"context"
"fmt"
"sync/atomic"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-car"
offline "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-merkledag"
peer "github.com/libp2p/go-libp2p-peer"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/wallet"
@ -38,13 +42,15 @@ type ChainGen struct {
cs *store.ChainStore
genesis *types.BlockHeader
curBlock *types.FullBlock
sm *stmgr.StateManager
genesis *types.BlockHeader
curTipset *store.FullTipSet
w *wallet.Wallet
miner address.Address
mworker address.Address
miners []address.Address
mworkers []address.Address
receivers []address.Address
banker address.Address
bankerNonce uint64
@ -116,8 +122,9 @@ func NewGenerator() (*ChainGen, error) {
}
minercfg := &GenMinerCfg{
Worker: worker,
Owner: worker,
Workers: []address.Address{worker, worker},
Owners: []address.Address{worker, worker},
PeerIDs: []peer.ID{"peerID1", "peerID2"},
}
genb, err := MakeGenesisBlock(bs, map[address.Address]types.BigInt{
@ -131,28 +138,32 @@ func NewGenerator() (*ChainGen, error) {
cs := store.NewChainStore(bs, ds)
genfb := &types.FullBlock{Header: genb.Genesis}
gents := store.NewFullTipSet([]*types.FullBlock{genfb})
if err := cs.SetGenesis(genb.Genesis); err != nil {
return nil, xerrors.Errorf("set genesis failed: %w", err)
}
if minercfg.MinerAddr == address.Undef {
if len(minercfg.MinerAddrs) == 0 {
return nil, xerrors.Errorf("MakeGenesisBlock failed to set miner address")
}
sm := stmgr.NewStateManager(cs)
gen := &ChainGen{
bs: bs,
cs: cs,
sm: sm,
msgsPerBlock: msgsPerBlock,
genesis: genb.Genesis,
w: w,
miner: minercfg.MinerAddr,
mworker: worker,
miners: minercfg.MinerAddrs,
mworkers: minercfg.Workers,
banker: banker,
receivers: receievers,
curBlock: genfb,
curTipset: gents,
r: mr,
lr: lr,
@ -179,19 +190,34 @@ func (cg *ChainGen) GenesisCar() ([]byte, error) {
return out.Bytes(), nil
}
func (cg *ChainGen) nextBlockProof(ctx context.Context) (address.Address, types.ElectionProof, []*types.Ticket, error) {
func (cg *ChainGen) nextBlockProof(ctx context.Context, m address.Address, ticks []*types.Ticket) (types.ElectionProof, *types.Ticket, error) {
pts := cg.curTipset.TipSet()
ticks := cg.curBlock.Header.Tickets
lastTicket := ticks[len(ticks)-1]
var lastTicket *types.Ticket
if len(ticks) == 0 {
lastTicket = pts.MinTicket()
} else {
lastTicket = ticks[len(ticks)-1]
}
vrfout, err := ComputeVRF(ctx, cg.w.Sign, cg.mworker, lastTicket.VDFResult)
st, err := cg.sm.TipSetState(pts.Cids())
if err != nil {
return address.Undef, nil, nil, err
return nil, nil, err
}
worker, err := stmgr.GetMinerWorker(ctx, cg.sm, st, m)
if err != nil {
return nil, nil, err
}
vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, lastTicket.VDFResult)
if err != nil {
return nil, nil, err
}
out, proof, err := vdf.Run(vrfout)
if err != nil {
return address.Undef, nil, nil, err
return nil, nil, err
}
tick := &types.Ticket{
@ -200,17 +226,77 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context) (address.Address, types.
VDFResult: out,
}
return cg.miner, []byte("cat in a box"), []*types.Ticket{tick}, nil
}
func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error) {
miner, proof, tickets, err := cg.nextBlockProof(context.TODO())
win, eproof, err := IsRoundWinner(ctx, pts, append(ticks, tick), m, &mca{w: cg.w, sm: cg.sm})
if err != nil {
return nil, nil, err
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
if !win {
return nil, tick, nil
}
// make some transfers from banker
return eproof, tick, nil
}
type MinedTipSet struct {
TipSet *store.FullTipSet
Messages []*types.SignedMessage
}
func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) {
var blks []*types.FullBlock
ticketSets := make([][]*types.Ticket, len(cg.miners))
msgs, err := cg.getRandomMessages()
if err != nil {
return nil, err
}
base := cg.curTipset.TipSet()
for len(blks) == 0 {
for i, m := range cg.miners {
proof, t, err := cg.nextBlockProof(context.TODO(), m, ticketSets[i])
if err != nil {
return nil, err
}
ticketSets[i] = append(ticketSets[i], t)
if proof != nil {
fblk, err := cg.makeBlock(base, m, proof, ticketSets[i], msgs)
if err != nil {
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
}
if err := cg.cs.AddBlock(fblk.Header); err != nil {
return nil, err
}
blks = append(blks, fblk)
}
}
}
cg.curTipset = store.NewFullTipSet(blks)
return &MinedTipSet{
TipSet: cg.curTipset,
Messages: msgs,
}, nil
}
func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, eproof types.ElectionProof, tickets []*types.Ticket, msgs []*types.SignedMessage) (*types.FullBlock, error) {
ts := parents.MinTimestamp() + (uint64(len(tickets)) * build.BlockDelay)
fblk, err := MinerCreateBlock(context.TODO(), cg.sm, cg.w, m, parents, tickets, eproof, msgs, ts)
if err != nil {
return nil, err
}
return fblk, err
}
func (cg *ChainGen) getRandomMessages() ([]*types.SignedMessage, error) {
msgs := make([]*types.SignedMessage, cg.msgsPerBlock)
for m := range msgs {
msg := types.Message{
@ -229,12 +315,12 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
unsigned, err := msg.Serialize()
if err != nil {
return nil, nil, err
return nil, err
}
sig, err := cg.w.Sign(context.TODO(), cg.banker, unsigned)
if err != nil {
return nil, nil, err
return nil, err
}
msgs[m] = &types.SignedMessage{
@ -243,31 +329,11 @@ func (cg *ChainGen) NextBlock() (*types.FullBlock, []*types.SignedMessage, error
}
if _, err := cg.cs.PutMessage(msgs[m]); err != nil {
return nil, nil, err
return nil, err
}
}
// create block
parents, err := types.NewTipSet([]*types.BlockHeader{cg.curBlock.Header})
if err != nil {
return nil, nil, err
}
ts := parents.MinTimestamp() + (uint64(len(tickets)) * build.BlockDelay)
fblk, err := MinerCreateBlock(context.TODO(), cg.cs, cg.w, miner, parents, tickets, proof, msgs, ts)
if err != nil {
return nil, nil, err
}
if err := cg.cs.AddBlock(fblk.Header); err != nil {
return nil, nil, err
}
cg.curBlock = fblk
return fblk, msgs, nil
return msgs, nil
}
func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
@ -276,3 +342,86 @@ func (cg *ChainGen) YieldRepo() (repo.Repo, error) {
}
return cg.r, nil
}
type MiningCheckAPI interface {
ChainGetRandomness(context.Context, *types.TipSet, []*types.Ticket, int) ([]byte, error)
StateMinerPower(context.Context, address.Address, *types.TipSet) (api.MinerPower, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
WalletSign(context.Context, address.Address, []byte) (*types.Signature, error)
}
type mca struct {
w *wallet.Wallet
sm *stmgr.StateManager
}
func (mca mca) ChainGetRandomness(ctx context.Context, pts *types.TipSet, ticks []*types.Ticket, lb int) ([]byte, error) {
return mca.sm.ChainStore().GetRandomness(ctx, pts, ticks, lb)
}
func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) {
mpow, tpow, err := stmgr.GetPower(ctx, mca.sm, ts, maddr)
if err != nil {
return api.MinerPower{}, err
}
return api.MinerPower{
MinerPower: mpow,
TotalPower: tpow,
}, err
}
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
st, err := mca.sm.TipSetState(ts.Cids())
if err != nil {
return address.Undef, err
}
return stmgr.GetMinerWorker(ctx, mca.sm, st, maddr)
}
func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) {
return mca.w.Sign(ctx, a, v)
}
func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) {
r, err := a.ChainGetRandomness(ctx, ts, ticks, build.RandomnessLookback)
if err != nil {
return false, nil, err
}
mworker, err := a.StateMinerWorker(ctx, miner, ts)
if err != nil {
return false, nil, xerrors.Errorf("failed to get miner worker: %w", err)
}
vrfout, err := ComputeVRF(ctx, a.WalletSign, mworker, r)
if err != nil {
return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
}
pow, err := a.StateMinerPower(ctx, miner, ts)
if err != nil {
return false, nil, xerrors.Errorf("failed to check power: %w", err)
}
return types.PowerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil
}
type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error)
func ComputeVRF(ctx context.Context, sign SignFunc, w address.Address, input []byte) ([]byte, error) {
sig, err := sign(ctx, w, input)
if err != nil {
return nil, err
}
if sig.Type != types.KTBLS {
return nil, fmt.Errorf("miner worker address was not a BLS key")
}
return sig.Data, nil
}

View File

@ -12,14 +12,18 @@ func testGeneration(t testing.TB, n int, msgs int) {
g.msgsPerBlock = msgs
var height int
for i := 0; i < n; i++ {
b, _, err := g.NextBlock()
mts, err := g.NextTipSet()
if err != nil {
t.Fatalf("error at H:%d, %s", i, err)
}
if b.Header.Height != uint64(i+1) {
t.Fatal("wrong height")
ts := mts.TipSet.TipSet()
if ts.Height() != uint64(height+len(ts.Blocks()[0].Tickets)) {
t.Fatal("wrong height", ts.Height(), i, len(ts.Blocks()[0].Tickets), len(ts.Blocks()))
}
height += len(ts.Blocks()[0].Tickets)
}
}

View File

@ -2,40 +2,41 @@ package gen
import (
"context"
"github.com/filecoin-project/go-bls-sigs"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
bls "github.com/filecoin-project/go-bls-sigs"
cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
"github.com/pkg/errors"
"github.com/whyrusleeping/sharray"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"github.com/filecoin-project/go-lotus/chain/wallet"
)
func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Wallet, miner address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, timestamp uint64) (*types.FullBlock, error) {
st, err := cs.TipSetState(parents.Cids())
func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wallet, miner address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, timestamp uint64) (*types.FullBlock, error) {
st, err := sm.TipSetState(parents.Cids())
if err != nil {
return nil, errors.Wrap(err, "failed to load tipset state")
}
height := parents.Height() + uint64(len(tickets))
vmi, err := vm.NewVM(st, height, miner, cs)
vmi, err := vm.NewVM(st, height, miner, sm.ChainStore())
if err != nil {
return nil, err
}
owner, err := getMinerOwner(ctx, cs, st, miner)
owner, err := stmgr.GetMinerOwner(ctx, sm, st, miner)
if err != nil {
return nil, xerrors.Errorf("failed to get miner owner: %w", err)
}
worker, err := getMinerWorker(ctx, cs, st, miner)
worker, err := stmgr.GetMinerWorker(ctx, sm, st, miner)
if err != nil {
return nil, xerrors.Errorf("failed to get miner worker: %w", err)
}
@ -46,11 +47,12 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Walle
}
next := &types.BlockHeader{
Miner: miner,
Parents: parents.Cids(),
Tickets: tickets,
Height: height,
Timestamp: timestamp,
Miner: miner,
Parents: parents.Cids(),
Tickets: tickets,
Height: height,
Timestamp: timestamp,
ElectionProof: proof,
}
var blsMessages []*types.Message
@ -63,7 +65,7 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Walle
blsSigs = append(blsSigs, msg.Signature)
blsMessages = append(blsMessages, &msg.Message)
c, err := cs.PutMessage(&msg.Message)
c, err := sm.ChainStore().PutMessage(&msg.Message)
if err != nil {
return nil, err
}
@ -93,7 +95,7 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Walle
receipts = append(receipts, rec.MessageReceipt)
}
cst := hamt.CSTFromBstore(cs.Blockstore())
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
blsmsgroot, err := sharray.Build(context.TODO(), 4, toIfArr(blsMsgCids), cst)
if err != nil {
return nil, err
@ -130,7 +132,7 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Walle
next.BLSAggregate = aggSig
next.StateRoot = stateRoot
pweight := cs.Weight(parents)
pweight := sm.ChainStore().Weight(parents)
next.ParentWeight = types.NewInt(pweight)
// TODO: set timestamp
@ -161,40 +163,6 @@ func MinerCreateBlock(ctx context.Context, cs *store.ChainStore, w *wallet.Walle
return fullBlock, nil
}
func getMinerWorker(ctx context.Context, cs *store.ChainStore, state cid.Cid, maddr address.Address) (address.Address, error) {
rec, err := vm.CallRaw(ctx, cs, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, state, 0)
if err != nil {
return address.Undef, err
}
if rec.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getWorker failed with exit code %d", rec.ExitCode)
}
return address.NewFromBytes(rec.Return)
}
func getMinerOwner(ctx context.Context, cs *store.ChainStore, state cid.Cid, maddr address.Address) (address.Address, error) {
rec, err := vm.CallRaw(ctx, cs, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetOwner,
}, state, 0)
if err != nil {
return address.Undef, err
}
if rec.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getOwner failed with exit code %d", rec.ExitCode)
}
return address.NewFromBytes(rec.Return)
}
func aggregateSignatures(sigs []types.Signature) (types.Signature, error) {
var blsSigs []bls.Signature
for _, s := range sigs {

View File

@ -140,16 +140,16 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) {
}
type GenMinerCfg struct {
Owner address.Address
Worker address.Address
Owners []address.Address
Workers []address.Address
// not quite generating real sectors yet, but this will be necessary
//SectorDir string
// The address of the created miner, this is set by the genesis setup
MinerAddr address.Address
// The addresses of the created miner, this is set by the genesis setup
MinerAddrs []address.Address
PeerID peer.ID
PeerIDs []peer.ID
}
func mustEnc(i interface{}) []byte {
@ -166,67 +166,78 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
}
params := mustEnc(actors.CreateStorageMinerParams{
Owner: gmcfg.Owner,
Worker: gmcfg.Worker,
SectorSize: types.NewInt(build.SectorSize),
PeerID: gmcfg.PeerID,
})
for i := 0; i < len(gmcfg.Workers); i++ {
owner := gmcfg.Owners[i]
worker := gmcfg.Workers[i]
pid := gmcfg.PeerIDs[i]
rval, err := doExec(ctx, vm, actors.StorageMarketAddress, gmcfg.Owner, actors.SMAMethods.CreateStorageMiner, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
params := mustEnc(actors.CreateStorageMinerParams{
Owner: owner,
Worker: worker,
SectorSize: types.NewInt(build.SectorSize),
PeerID: pid,
})
rval, err := doExec(ctx, vm, actors.StorageMarketAddress, owner, actors.SMAMethods.CreateStorageMiner, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err)
}
maddr, err := address.NewFromBytes(rval)
if err != nil {
return cid.Undef, err
}
gmcfg.MinerAddrs = append(gmcfg.MinerAddrs, maddr)
params = mustEnc(actors.UpdateStorageParams{Delta: types.NewInt(5000)})
_, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SMAMethods.UpdateStorage, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
}
// UGLY HACKY MODIFICATION OF MINER POWER
// we have to flush the vm here because it buffers stuff internally for perf reasons
if _, err := vm.Flush(ctx); err != nil {
return cid.Undef, xerrors.Errorf("vm.Flush failed: %w", err)
}
st := vm.StateTree()
mact, err := st.GetActor(maddr)
if err != nil {
return cid.Undef, xerrors.Errorf("get miner actor failed: %w", err)
}
cst := hamt.CSTFromBstore(cs.Blockstore())
var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return cid.Undef, xerrors.Errorf("getting miner actor state failed: %w", err)
}
mstate.Power = types.NewInt(5000)
nstate, err := cst.Put(ctx, mstate)
if err != nil {
return cid.Undef, err
}
mact.Head = nstate
if err := st.SetActor(maddr, mact); err != nil {
return cid.Undef, err
}
// End of super haxx
}
maddr, err := address.NewFromBytes(rval)
if err != nil {
return cid.Undef, err
}
gmcfg.MinerAddr = maddr
params = mustEnc(actors.UpdateStorageParams{Delta: types.NewInt(5000)})
_, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SMAMethods.UpdateStorage, params)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err)
}
// UGLY HACKY MODIFICATION OF MINER POWER
// we have to flush the vm here because it buffers stuff internally for perf reasons
if _, err := vm.Flush(ctx); err != nil {
return cid.Undef, xerrors.Errorf("vm.Flush failed: %w", err)
}
st := vm.StateTree()
mact, err := st.GetActor(maddr)
if err != nil {
return cid.Undef, xerrors.Errorf("get miner actor failed: %w", err)
}
cst := hamt.CSTFromBstore(cs.Blockstore())
var mstate actors.StorageMinerActorState
if err := cst.Get(ctx, mact.Head, &mstate); err != nil {
return cid.Undef, xerrors.Errorf("getting miner actor state failed: %w", err)
}
mstate.Power = types.NewInt(5000)
nstate, err := cst.Put(ctx, mstate)
if err != nil {
return cid.Undef, err
}
mact.Head = nstate
if err := st.SetActor(maddr, mact); err != nil {
return cid.Undef, err
}
// End of super haxx
return vm.Flush(ctx)
}
func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uint64, params []byte) ([]byte, error) {
act, err := vm.StateTree().GetActor(from)
if err != nil {
return nil, xerrors.Errorf("doExec failed to get from actor: %w", err)
}
ret, err := vm.ApplyMessage(context.TODO(), &types.Message{
To: to,
From: from,
@ -235,6 +246,7 @@ func doExec(ctx context.Context, vm *vm.VM, to, from address.Address, method uin
GasLimit: types.NewInt(1000000),
GasPrice: types.NewInt(0),
Value: types.NewInt(0),
Nonce: act.Nonce,
})
if err != nil {
return nil, err
@ -322,19 +334,3 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
Genesis: b,
}, nil
}
type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error)
func ComputeVRF(ctx context.Context, sign SignFunc, w address.Address, input []byte) ([]byte, error) {
sig, err := sign(ctx, w, input)
if err != nil {
return nil, err
}
if sig.Type != types.KTBLS {
return nil, fmt.Errorf("miner worker address was not a BLS key")
}
return sig.Data, nil
}

View File

@ -5,7 +5,7 @@ import (
"sync"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/pkg/errors"
)
@ -15,7 +15,7 @@ type MessagePool struct {
pending map[address.Address]*msgSet
cs *store.ChainStore
sm *stmgr.StateManager
}
type msgSet struct {
@ -36,12 +36,12 @@ func (ms *msgSet) add(m *types.SignedMessage) {
ms.msgs[m.Message.Nonce] = m
}
func NewMessagePool(cs *store.ChainStore) *MessagePool {
func NewMessagePool(sm *stmgr.StateManager) *MessagePool {
mp := &MessagePool{
pending: make(map[address.Address]*msgSet),
cs: cs,
sm: sm,
}
cs.SubscribeHeadChanges(mp.HeadChange)
sm.ChainStore().SubscribeHeadChanges(mp.HeadChange)
return mp
}
@ -61,7 +61,7 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error {
return err
}
if _, err := mp.cs.PutMessage(m); err != nil {
if _, err := mp.sm.ChainStore().PutMessage(m); err != nil {
return err
}
@ -84,7 +84,7 @@ func (mp *MessagePool) GetNonce(addr address.Address) (uint64, error) {
return mset.startNonce + uint64(len(mset.msgs)), nil
}
act, err := mp.cs.GetActor(addr)
act, err := mp.sm.GetActor(addr)
if err != nil {
return 0, err
}
@ -130,7 +130,7 @@ func (mp *MessagePool) Pending() []*types.SignedMessage {
func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet) error {
for _, ts := range revert {
for _, b := range ts.Blocks() {
bmsgs, smsgs, err := mp.cs.MessagesForBlock(b)
bmsgs, smsgs, err := mp.sm.ChainStore().MessagesForBlock(b)
if err != nil {
return errors.Wrapf(err, "failed to get messages for revert block %s(height %d)", b.Cid(), b.Height)
}
@ -155,7 +155,7 @@ func (mp *MessagePool) HeadChange(revert []*types.TipSet, apply []*types.TipSet)
for _, ts := range apply {
for _, b := range ts.Blocks() {
bmsgs, smsgs, err := mp.cs.MessagesForBlock(b)
bmsgs, smsgs, err := mp.sm.ChainStore().MessagesForBlock(b)
if err != nil {
return errors.Wrapf(err, "failed to get messages for apply block %s(height %d) (msgroot = %s)", b.Cid(), b.Height, b.Messages)
}

View File

@ -1,17 +1,18 @@
package vm
package stmgr
import (
"context"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
cid "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
)
func CallRaw(ctx context.Context, cs *store.ChainStore, msg *types.Message, bstate cid.Cid, bheight uint64) (*types.MessageReceipt, error) {
vmi, err := NewVM(bstate, bheight, actors.NetworkAddress, cs)
func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate cid.Cid, bheight uint64) (*types.MessageReceipt, error) {
vmi, err := vm.NewVM(bstate, bheight, actors.NetworkAddress, sm.cs)
if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err)
}
@ -32,7 +33,7 @@ func CallRaw(ctx context.Context, cs *store.ChainStore, msg *types.Message, bsta
}
}
fromActor, err := vmi.cstate.GetActor(msg.From)
fromActor, err := vmi.StateTree().GetActor(msg.From)
if err != nil {
return nil, err
}
@ -52,15 +53,15 @@ func CallRaw(ctx context.Context, cs *store.ChainStore, msg *types.Message, bsta
}
func Call(ctx context.Context, cs *store.ChainStore, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
if ts == nil {
ts = cs.GetHeaviestTipSet()
ts = sm.cs.GetHeaviestTipSet()
}
state, err := cs.TipSetState(ts.Cids())
state, err := sm.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
return CallRaw(ctx, cs, msg, state, ts.Height())
return sm.CallRaw(ctx, msg, state, ts.Height())
}

165
chain/stmgr/stmgr.go Normal file
View File

@ -0,0 +1,165 @@
package stmgr
import (
"context"
"sync"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"golang.org/x/xerrors"
"github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
logging "github.com/ipfs/go-log"
)
var log = logging.Logger("statemgr")
type StateManager struct {
cs *store.ChainStore
stCache map[string]cid.Cid
stlk sync.Mutex
}
func NewStateManager(cs *store.ChainStore) *StateManager {
return &StateManager{
cs: cs,
stCache: make(map[string]cid.Cid),
}
}
func cidsToKey(cids []cid.Cid) string {
var out string
for _, c := range cids {
out += c.KeyString()
}
return out
}
func (sm *StateManager) TipSetState(cids []cid.Cid) (cid.Cid, error) {
ck := cidsToKey(cids)
sm.stlk.Lock()
cached, ok := sm.stCache[ck]
sm.stlk.Unlock()
if ok {
return cached, nil
}
out, err := sm.computeTipSetState(cids)
if err != nil {
return cid.Undef, err
}
sm.stlk.Lock()
sm.stCache[ck] = out
sm.stlk.Unlock()
return out, nil
}
func (sm *StateManager) computeTipSetState(cids []cid.Cid) (cid.Cid, error) {
ctx := context.TODO()
ts, err := sm.cs.LoadTipSet(cids)
if err != nil {
log.Error("failed loading tipset: ", cids)
return cid.Undef, err
}
if len(ts.Blocks()) == 1 {
return ts.Blocks()[0].StateRoot, nil
}
pstate, err := sm.TipSetState(ts.Parents())
if err != nil {
return cid.Undef, xerrors.Errorf("recursive TipSetState failed: %w", err)
}
vmi, err := vm.NewVM(pstate, ts.Height(), address.Undef, sm.cs)
if err != nil {
return cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
}
applied := make(map[cid.Cid]bool)
for _, b := range ts.Blocks() {
vmi.SetBlockMiner(b.Miner)
bms, sms, err := sm.cs.MessagesForBlock(b)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to get messages for block: %w", err)
}
for _, m := range bms {
if applied[m.Cid()] {
continue
}
applied[m.Cid()] = true
_, err := vmi.ApplyMessage(ctx, m)
if err != nil {
return cid.Undef, err
}
}
for _, sm := range sms {
if applied[sm.Cid()] {
continue
}
applied[sm.Cid()] = true
_, err := vmi.ApplyMessage(ctx, &sm.Message)
if err != nil {
return cid.Undef, err
}
}
}
return vmi.Flush(ctx)
}
func (sm *StateManager) GetActor(addr address.Address) (*types.Actor, error) {
ts := sm.cs.GetHeaviestTipSet()
stcid, err := sm.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
state, err := state.LoadStateTree(cst, stcid)
if err != nil {
return nil, err
}
return state.GetActor(addr)
}
func (sm *StateManager) GetBalance(addr address.Address) (types.BigInt, error) {
act, err := sm.GetActor(addr)
if err != nil {
return types.BigInt{}, err
}
return act.Balance, nil
}
func (sm *StateManager) ChainStore() *store.ChainStore {
return sm.cs
}
func (sm *StateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}) (*types.Actor, error) {
act, err := sm.GetActor(a)
if err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
if err := cst.Get(ctx, act.Head, out); err != nil {
return nil, err
}
return act, nil
}

106
chain/stmgr/utils.go Normal file
View File

@ -0,0 +1,106 @@
package stmgr
import (
"context"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/types"
cid "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
)
func GetMinerWorker(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
recp, err := sm.CallRaw(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, st, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner worker addr failed (exit code %d)", recp.ExitCode)
}
worker, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if worker.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve worker address to a pubkeyaddr")
}
return worker, nil
}
func GetMinerOwner(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
recp, err := sm.CallRaw(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetOwner,
}, st, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner owner addr failed (exit code %d)", recp.ExitCode)
}
owner, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if owner.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve owner address to a pubkeyaddr")
}
return owner, nil
}
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (types.BigInt, types.BigInt, error) {
var err error
enc, err := actors.SerializeParams(&actors.PowerLookupParams{maddr})
if err != nil {
return types.EmptyInt, types.EmptyInt, err
}
var mpow types.BigInt
if maddr != address.Undef {
ret, err := sm.Call(ctx, &types.Message{
From: maddr,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.PowerLookup,
Params: enc,
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain (exit code %d)", ret.ExitCode)
}
mpow = types.BigFromBytes(ret.Return)
}
ret, err := sm.Call(ctx, &types.Message{
From: actors.StorageMarketAddress,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.GetTotalStorage,
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain (exit code %d)", ret.ExitCode)
}
tpow := types.BigFromBytes(ret.Return)
return mpow, tpow, nil
}

View File

@ -2,13 +2,13 @@ package store
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"sync"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/types"
"golang.org/x/xerrors"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
@ -35,6 +35,9 @@ type ChainStore struct {
bestTips *pubsub.PubSub
tstLk sync.Mutex
tipsets map[uint64][]cid.Cid
headChangeNotifs []func(rev, app []*types.TipSet) error
}
@ -43,6 +46,7 @@ func NewChainStore(bs bstore.Blockstore, ds dstore.Batching) *ChainStore {
bs: bs,
ds: ds,
bestTips: pubsub.New(64),
tipsets: make(map[uint64][]cid.Cid),
}
hcnf := func(rev, app []*types.TipSet) error {
@ -175,7 +179,13 @@ func (cs *ChainStore) PutTipSet(ts *FullTipSet) error {
}
}
if err := cs.MaybeTakeHeavierTipSet(ts.TipSet()); err != nil {
expanded, err := cs.expandTipset(ts.TipSet().Blocks()[0])
if err != nil {
return xerrors.Errorf("errored while expanding tipset: %w", err)
}
fmt.Printf("expanded %s into %s\n", ts.TipSet().Cids(), expanded.Cids())
if err := cs.MaybeTakeHeavierTipSet(expanded); err != nil {
return errors.Wrap(err, "MaybeTakeHeavierTipSet failed in PutTipSet")
}
return nil
@ -317,12 +327,35 @@ func (cs *ChainStore) GetHeaviestTipSet() *types.TipSet {
return cs.heaviest
}
func (cs *ChainStore) addToTipSetTracker(b *types.BlockHeader) error {
cs.tstLk.Lock()
defer cs.tstLk.Unlock()
tss := cs.tipsets[b.Height]
for _, oc := range tss {
if oc == b.Cid() {
log.Warn("tried to add block to tipset tracker that was already there")
return nil
}
}
cs.tipsets[b.Height] = append(tss, b.Cid())
// TODO: do we want to look for slashable submissions here? might as well...
return nil
}
func (cs *ChainStore) PersistBlockHeader(b *types.BlockHeader) error {
sb, err := b.ToStorageBlock()
if err != nil {
return err
}
if err := cs.addToTipSetTracker(b); err != nil {
return xerrors.Errorf("failed to insert new block (%s) into tipset tracker: %w", b.Cid(), err)
}
return cs.bs.Put(sb)
}
@ -365,12 +398,49 @@ func (cs *ChainStore) PutMessage(m storable) (cid.Cid, error) {
return PutMessage(cs.bs, m)
}
func (cs *ChainStore) expandTipset(b *types.BlockHeader) (*types.TipSet, error) {
// Hold lock for the whole function for now, if it becomes a problem we can
// fix pretty easily
cs.tstLk.Lock()
defer cs.tstLk.Unlock()
all := []*types.BlockHeader{b}
tsets, ok := cs.tipsets[b.Height]
if !ok {
return types.NewTipSet(all)
}
for _, bhc := range tsets {
if bhc == b.Cid() {
continue
}
h, err := cs.GetBlock(bhc)
if err != nil {
return nil, xerrors.Errorf("failed to load block (%s) for tipset expansion: %w", bhc, err)
}
if types.CidArrsEqual(h.Parents, b.Parents) {
all = append(all, h)
}
}
// TODO: other validation...?
return types.NewTipSet(all)
}
func (cs *ChainStore) AddBlock(b *types.BlockHeader) error {
if err := cs.PersistBlockHeader(b); err != nil {
return err
}
ts, _ := types.NewTipSet([]*types.BlockHeader{b})
ts, err := cs.expandTipset(b)
if err != nil {
return err
}
if err := cs.MaybeTakeHeavierTipSet(ts); err != nil {
return errors.Wrap(err, "MaybeTakeHeavierTipSet failed")
}
@ -397,21 +467,6 @@ func (cs *ChainStore) GetGenesis() (*types.BlockHeader, error) {
return types.DecodeBlock(genb.RawData())
}
func (cs *ChainStore) TipSetState(cids []cid.Cid) (cid.Cid, error) {
ts, err := cs.LoadTipSet(cids)
if err != nil {
log.Error("failed loading tipset: ", cids)
return cid.Undef, err
}
if len(ts.Blocks()) == 1 {
return ts.Blocks()[0].StateRoot, nil
}
panic("cant handle multiblock tipsets yet")
}
func (cs *ChainStore) GetMessage(c cid.Cid) (*types.Message, error) {
sb, err := cs.bs.Get(c)
if err != nil {
@ -460,7 +515,7 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message,
cst := hamt.CSTFromBstore(cs.bs)
var msgmeta types.MsgMeta
if err := cst.Get(context.TODO(), b.Messages, &msgmeta); err != nil {
return nil, nil, err
return nil, nil, xerrors.Errorf("failed to load msgmeta: %w", err)
}
blscids, err := cs.readSharrayCids(msgmeta.BlsMessages)
@ -539,31 +594,6 @@ func (cs *ChainStore) LoadSignedMessagesFromCids(cids []cid.Cid) ([]*types.Signe
return msgs, nil
}
func (cs *ChainStore) GetBalance(addr address.Address) (types.BigInt, error) {
act, err := cs.GetActor(addr)
if err != nil {
return types.BigInt{}, err
}
return act.Balance, nil
}
func (cs *ChainStore) GetActor(addr address.Address) (*types.Actor, error) {
ts := cs.GetHeaviestTipSet()
stcid, err := cs.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(cs.bs)
state, err := state.LoadStateTree(cst, stcid)
if err != nil {
return nil, err
}
return state.GetActor(addr)
}
func (cs *ChainStore) WaitForMessage(ctx context.Context, mcid cid.Cid) (cid.Cid, *types.MessageReceipt, error) {
tsub := cs.SubHeadChanges(ctx)
@ -672,3 +702,47 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
}
return NewFullTipSet(out), nil
}
func (cs *ChainStore) GetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int) ([]byte, error) {
if lb < len(tickets) {
log.Warn("self sampling randomness. this should be extremely rare, if you see this often it may be a bug")
t := tickets[len(tickets)-(1+lb)]
return t.VDFResult, nil
}
nv := lb - len(tickets)
nextCids := pts.Cids()
for {
nts, err := cs.LoadTipSet(nextCids)
if err != nil {
return nil, err
}
mtb := nts.MinTicketBlock()
if nv < len(mtb.Tickets) {
t := mtb.Tickets[len(mtb.Tickets)-(1+nv)]
return t.VDFResult, nil
}
nv -= len(mtb.Tickets)
// special case for lookback behind genesis block
// TODO(spec): this is not in the spec, need to sync that
if mtb.Height == 0 {
t := mtb.Tickets[0]
rval := t.VDFResult
for i := 0; i < nv; i++ {
h := sha256.Sum256(rval)
rval = h[:]
}
return rval, nil
}
nextCids = mtb.Parents
}
}

View File

@ -11,6 +11,7 @@ import (
"github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
@ -34,6 +35,9 @@ type Syncer struct {
// The interface for accessing and putting tipsets into local storage
store *store.ChainStore
// the state manager handles making state queries
sm *stmgr.StateManager
// The known Genesis tipset
Genesis *types.TipSet
@ -53,8 +57,8 @@ type Syncer struct {
peerHeadsLk sync.Mutex
}
func NewSyncer(cs *store.ChainStore, bsync *BlockSync, self peer.ID) (*Syncer, error) {
gen, err := cs.GetGenesis()
func NewSyncer(sm *stmgr.StateManager, bsync *BlockSync, self peer.ID) (*Syncer, error) {
gen, err := sm.ChainStore().GetGenesis()
if err != nil {
return nil, err
}
@ -68,7 +72,8 @@ func NewSyncer(cs *store.ChainStore, bsync *BlockSync, self peer.ID) (*Syncer, e
Genesis: gent,
Bsync: bsync,
peerHeads: make(map[peer.ID]*types.TipSet),
store: cs,
store: sm.ChainStore(),
sm: sm,
self: self,
}, nil
}
@ -320,7 +325,7 @@ func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, b
return err
}
ret, err := vm.Call(ctx, syncer.store, &types.Message{
ret, err := syncer.sm.Call(ctx, &types.Message{
To: actors.StorageMarketAddress,
From: maddr,
Method: actors.SMAMethods.IsMiner,
@ -353,7 +358,6 @@ func (syncer *Syncer) validateTickets(ctx context.Context, mworker address.Addre
Data: next.VRFProof,
}
log.Infof("About to verify signature: ", sig.Data, mworker, cur.VDFResult)
if err := sig.Verify(mworker, cur.VDFResult); err != nil {
return xerrors.Errorf("invalid ticket, VRFProof invalid: %w", err)
}
@ -369,62 +373,10 @@ func (syncer *Syncer) validateTickets(ctx context.Context, mworker address.Addre
return nil
}
func getMinerWorker(ctx context.Context, cs *store.ChainStore, st cid.Cid, maddr address.Address) (address.Address, error) {
recp, err := vm.CallRaw(ctx, cs, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, st, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner worker addr failed (exit code %d)", recp.ExitCode)
}
worker, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if worker.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve worker address to a pubkeyaddr")
}
return worker, nil
}
func getMinerOwner(ctx context.Context, cs *store.ChainStore, st cid.Cid, maddr address.Address) (address.Address, error) {
recp, err := vm.CallRaw(ctx, cs, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetOwner,
}, st, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner owner addr failed (exit code %d)", recp.ExitCode)
}
owner, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if owner.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve owner address to a pubkeyaddr")
}
return owner, nil
}
// 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
stateroot, err := syncer.store.TipSetState(h.Parents)
stateroot, err := syncer.sm.TipSetState(h.Parents)
if err != nil {
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
}
@ -447,21 +399,39 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("minerIsValid failed: %w", err)
}
waddr, err := getMinerWorker(ctx, syncer.store, stateroot, h.Miner)
waddr, err := stmgr.GetMinerWorker(ctx, syncer.sm, stateroot, h.Miner)
if err != nil {
return xerrors.Errorf("getMinerWorker failed: %w", err)
return xerrors.Errorf("GetMinerWorker failed: %w", err)
}
if err := syncer.validateTickets(ctx, waddr, h.Tickets, baseTs); err != nil {
return xerrors.Errorf("validating block tickets failed: %w", err)
}
rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs, h.Tickets, build.RandomnessLookback)
if err != nil {
return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err)
}
if err := VerifyElectionProof(ctx, h.ElectionProof, rand, waddr); err != nil {
return xerrors.Errorf("checking eproof failed: %w", err)
}
mpow, tpow, err := stmgr.GetPower(ctx, syncer.sm, baseTs, h.Miner)
if err != nil {
return xerrors.Errorf("failed getting power: %w", err)
}
if !types.PowerCmp(h.ElectionProof, mpow, tpow) {
return xerrors.Errorf("miner created a block but was not a winner")
}
vmi, err := vm.NewVM(stateroot, h.Height, h.Miner, syncer.store)
if err != nil {
return xerrors.Errorf("failed to instantiate VM: %w", err)
}
owner, err := getMinerOwner(ctx, syncer.store, stateroot, b.Header.Miner)
owner, err := stmgr.GetMinerOwner(ctx, syncer.sm, stateroot, b.Header.Miner)
if err != nil {
return xerrors.Errorf("getting miner owner for block miner failed: %w", err)
}
@ -508,7 +478,6 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
}
return nil
}
func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*types.TipSet, error) {
@ -536,12 +505,16 @@ func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*t
at = ts.Parents()
}
loop:
for blockSet[len(blockSet)-1].Height() > untilHeight {
// NB: GetBlocks validates that the blocks are in-fact the ones we
// requested, and that they are correctly linked to eachother. It does
// not validate any state transitions
fmt.Println("Get blocks")
blks, err := syncer.Bsync.GetBlocks(context.TODO(), at, 10)
window := 10
if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window {
window = gap
}
blks, err := syncer.Bsync.GetBlocks(context.TODO(), at, window)
if err != nil {
// Most likely our peers aren't fully synced yet, but forwarded
// new block message (ideally we'd find better peers)
@ -554,7 +527,7 @@ func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*t
for _, b := range blks {
if b.Height() < untilHeight {
break
break loop
}
blockSet = append(blockSet, b)
}
@ -562,9 +535,18 @@ func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*t
at = blks[len(blks)-1].Parents()
}
if !cidArrsEqual(blockSet[len(blockSet)-1].Parents(), to.Cids()) {
// We have now ascertained that this is *not* a 'fast forward'
if !types.CidArrsEqual(blockSet[len(blockSet)-1].Parents(), to.Cids()) {
last := blockSet[len(blockSet)-1]
if types.CidArrsEqual(last.Parents(), to.Parents()) {
// common case: receiving a block thats potentially part of the same tipset as our best block
return blockSet, nil
}
// TODO: handle the case where we are on a fork and its not a simple fast forward
return nil, xerrors.Errorf("synced header chain does not link to our best block")
// need to walk back to either a common ancestor, or until we hit the fork length threshold.
return nil, xerrors.Errorf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", from.Cids(), from.Height(), to.Cids(), to.Height())
}
return blockSet, nil
@ -572,11 +554,12 @@ func (syncer *Syncer) collectHeaders(from *types.TipSet, to *types.TipSet) ([]*t
func (syncer *Syncer) syncMessagesAndCheckState(headers []*types.TipSet) error {
return syncer.iterFullTipsets(headers, func(fts *store.FullTipSet) error {
log.Warn("validating tipset: ", fts.TipSet().Height())
log.Warnf("validating tipset (heigt=%d, size=%d)", fts.TipSet().Height(), len(fts.TipSet().Cids()))
if err := syncer.ValidateTipSet(context.TODO(), fts); err != nil {
log.Errorf("failed to validate tipset: %s", err)
return xerrors.Errorf("message processing failed: %w", err)
}
return nil
})
}
@ -602,10 +585,6 @@ func (syncer *Syncer) iterFullTipsets(headers []*types.TipSet, cb func(*store.Fu
windowSize := 10
for i := len(headers) - 1; i >= 0; i -= windowSize {
// temp storage so we don't persist data we dont want to
ds := dstore.NewMapDatastore()
bs := bstore.NewBlockstore(ds)
cst := hamt.CSTFromBstore(bs)
batchSize := windowSize
if i < batchSize {
@ -619,6 +598,11 @@ func (syncer *Syncer) iterFullTipsets(headers []*types.TipSet, cb func(*store.Fu
}
for bsi := 0; bsi < len(bstips); bsi++ {
// temp storage so we don't persist data we dont want to
ds := dstore.NewMapDatastore()
bs := bstore.NewBlockstore(ds)
cst := hamt.CSTFromBstore(bs)
this := headers[i-bsi]
bstip := bstips[len(bstips)-(bsi+1)]
fts, err := zipTipSetAndMessages(cst, this, bstip.BlsMessages, bstip.SecpkMessages, bstip.BlsMsgIncludes, bstip.SecpkMsgIncludes)
@ -634,38 +618,37 @@ func (syncer *Syncer) iterFullTipsets(headers []*types.TipSet, cb func(*store.Fu
if err := cb(fts); err != nil {
return err
}
if err := persistMessages(bs, bstip); err != nil {
return err
}
if err := copyBlockstore(bs, syncer.store.Blockstore()); err != nil {
return xerrors.Errorf("message processing failed: %w", err)
}
}
if err := persistMessages(bs, bstips); err != nil {
return err
}
if err := copyBlockstore(bs, syncer.store.Blockstore()); err != nil {
return xerrors.Errorf("message processing failed: %w", err)
}
}
return nil
}
func persistMessages(bs bstore.Blockstore, bstips []*BSTipSet) error {
for _, bst := range bstips {
for _, m := range bst.BlsMessages {
//log.Infof("putting BLS message: %s", m.Cid())
if _, err := store.PutMessage(bs, m); err != nil {
log.Error("failed to persist messages: ", err)
return xerrors.Errorf("BLS message processing failed: %w", err)
}
func persistMessages(bs bstore.Blockstore, bst *BSTipSet) error {
for _, m := range bst.BlsMessages {
//log.Infof("putting BLS message: %s", m.Cid())
if _, err := store.PutMessage(bs, m); err != nil {
log.Error("failed to persist messages: ", err)
return xerrors.Errorf("BLS message processing failed: %w", err)
}
for _, m := range bst.SecpkMessages {
if m.Signature.Type != types.KTSecp256k1 {
return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.TypeCode)
}
//log.Infof("putting secp256k1 message: %s", m.Cid())
if _, err := store.PutMessage(bs, m); err != nil {
log.Error("failed to persist messages: ", err)
return xerrors.Errorf("secp256k1 message processing failed: %w", err)
}
}
for _, m := range bst.SecpkMessages {
if m.Signature.Type != types.KTSecp256k1 {
return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.TypeCode)
}
//log.Infof("putting secp256k1 message: %s", m.Cid())
if _, err := store.PutMessage(bs, m); err != nil {
log.Error("failed to persist messages: ", err)
return xerrors.Errorf("secp256k1 message processing failed: %w", err)
}
}
@ -692,3 +675,16 @@ func (syncer *Syncer) collectChain(fts *store.FullTipSet) error {
return nil
}
func VerifyElectionProof(ctx context.Context, eproof []byte, rand []byte, worker address.Address) error {
sig := types.Signature{
Data: eproof,
Type: types.KTBLS,
}
if err := sig.Verify(worker, rand); err != nil {
return xerrors.Errorf("failed to verify election proof signature: %w", err)
}
return nil
}

View File

@ -12,26 +12,27 @@ import (
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/gen"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/node"
"github.com/filecoin-project/go-lotus/node/impl"
"github.com/filecoin-project/go-lotus/node/modules"
"github.com/filecoin-project/go-lotus/node/repo"
)
const source = 0
func (tu *syncTestUtil) repoWithChain(t testing.TB, h int) (repo.Repo, []byte, []*types.FullBlock) {
blks := make([]*types.FullBlock, h)
func (tu *syncTestUtil) repoWithChain(t testing.TB, h int) (repo.Repo, []byte, []*store.FullTipSet) {
blks := make([]*store.FullTipSet, h)
for i := 0; i < h; i++ {
var err error
blks[i], _, err = tu.g.NextBlock()
mts, err := tu.g.NextTipSet()
require.NoError(t, err)
fmt.Printf("block at H:%d: %s\n", blks[i].Header.Height, blks[i].Cid())
blks[i] = mts.TipSet
ts := mts.TipSet.TipSet()
fmt.Printf("tipset at H:%d: %s\n", ts.Height(), ts.Cids())
require.Equal(t, uint64(i+1), blks[i].Header.Height, "wrong height")
}
r, err := tu.g.YieldRepo()
@ -54,7 +55,7 @@ type syncTestUtil struct {
g *gen.ChainGen
genesis []byte
blocks []*types.FullBlock
blocks []*store.FullTipSet
nds []api.FullNode
}
@ -79,7 +80,7 @@ func prepSyncTest(t testing.TB, h int) *syncTestUtil {
}
tu.addSourceNode(h)
tu.checkHeight("source", source, h)
//tu.checkHeight("source", source, h)
// separate logs
fmt.Println("\x1b[31m///////////////////////////////////////////////////\x1b[39b")
@ -92,14 +93,16 @@ func (tu *syncTestUtil) Shutdown() {
}
func (tu *syncTestUtil) mineNewBlock(src int) {
fblk, msgs, err := tu.g.NextBlock()
mts, err := tu.g.NextTipSet()
require.NoError(tu.t, err)
for _, msg := range msgs {
for _, msg := range mts.Messages {
require.NoError(tu.t, tu.nds[src].MpoolPush(context.TODO(), msg))
}
require.NoError(tu.t, tu.nds[src].ChainSubmitBlock(context.TODO(), fblkToBlkMsg(fblk)))
for _, fblk := range mts.TipSet.Blocks {
require.NoError(tu.t, tu.nds[src].ChainSubmitBlock(context.TODO(), fblkToBlkMsg(fblk)))
}
}
func fblkToBlkMsg(fb *types.FullBlock) *chain.BlockMsg {
@ -177,6 +180,17 @@ func (tu *syncTestUtil) checkHeight(name string, n int, h int) {
}
func (tu *syncTestUtil) compareSourceState(with int) {
sourceHead, err := tu.nds[source].ChainHead(tu.ctx)
require.NoError(tu.t, err)
targetHead, err := tu.nds[with].ChainHead(tu.ctx)
require.NoError(tu.t, err)
if !sourceHead.Equals(targetHead) {
fmt.Println("different chains: ", sourceHead.Height(), targetHead.Height())
tu.t.Fatalf("nodes were not synced correctly: %s != %s", sourceHead.Cids(), targetHead.Cids())
}
sourceAccounts, err := tu.nds[source].WalletList(tu.ctx)
require.NoError(tu.t, err)
@ -215,6 +229,7 @@ func (tu *syncTestUtil) waitUntilSync(from, to int) {
}
}
/*
func (tu *syncTestUtil) submitSourceBlock(to int, h int) {
// utility to simulate incoming blocks without miner process
// TODO: should call syncer directly, this won't work correctly in all cases
@ -238,29 +253,30 @@ func (tu *syncTestUtil) submitSourceBlocks(to int, h int, n int) {
tu.submitSourceBlock(to, h+i)
}
}
*/
func TestSyncSimple(t *testing.T) {
H := 50
tu := prepSyncTest(t, H)
client := tu.addClientNode()
tu.checkHeight("client", client, 0)
//tu.checkHeight("client", client, 0)
require.NoError(t, tu.mn.LinkAll())
tu.connect(1, 0)
tu.waitUntilSync(0, client)
tu.checkHeight("client", client, H)
//tu.checkHeight("client", client, H)
tu.compareSourceState(client)
}
func TestSyncMining(t *testing.T) {
H := 100
H := 50
tu := prepSyncTest(t, H)
client := tu.addClientNode()
tu.checkHeight("client", client, 0)
//tu.checkHeight("client", client, 0)
require.NoError(t, tu.mn.LinkAll())
tu.connect(client, 0)
@ -269,7 +285,7 @@ func TestSyncMining(t *testing.T) {
fmt.Println("after wait until sync")
tu.checkHeight("client", client, H)
//tu.checkHeight("client", client, H)
tu.compareSourceState(client)

View File

@ -2,6 +2,8 @@ package types
import (
"bytes"
"crypto/sha256"
"math/big"
block "github.com/ipfs/go-block-format"
"github.com/ipfs/go-cid"
@ -87,6 +89,10 @@ func (blk *BlockHeader) Serialize() ([]byte, error) {
return buf.Bytes(), nil
}
func (blk *BlockHeader) LastTicket() *Ticket {
return blk.Tickets[len(blk.Tickets)-1]
}
type MsgMeta struct {
BlsMessages cid.Cid
SecpkMessages cid.Cid
@ -114,3 +120,40 @@ func (mm *MsgMeta) ToStorageBlock() (block.Block, error) {
return block.NewBlockWithCid(buf.Bytes(), c)
}
func CidArrsEqual(a, b []cid.Cid) bool {
if len(a) != len(b) {
return false
}
// order ignoring compare...
s := make(map[cid.Cid]bool)
for _, c := range a {
s[c] = true
}
for _, c := range b {
if !s[c] {
return false
}
}
return true
}
func PowerCmp(eproof ElectionProof, mpow, totpow BigInt) bool {
/*
Need to check that
h(vrfout) / 2^256 < minerPower / totalPower
*/
h := sha256.Sum256(eproof)
// 2^256
rden := BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
top := BigMul(rden, mpow)
out := BigDiv(top, totpow)
return BigCmp(BigFromBytes(h[:]), out) < 0
}

View File

@ -96,19 +96,13 @@ func (ts *TipSet) Equals(ots *TipSet) bool {
return true
}
func (ts *TipSet) MinTicket() *Ticket {
if len(ts.Blocks()) == 0 {
panic("tipset has no blocks!")
}
var minTicket *Ticket
for _, b := range ts.Blocks() {
lastTicket := b.Tickets[len(b.Tickets)-1]
if minTicket == nil || bytes.Compare(lastTicket.VDFResult, minTicket.VDFResult) < 0 {
minTicket = lastTicket
}
}
func (t *Ticket) Less(o *Ticket) bool {
return bytes.Compare(t.VDFResult, o.VDFResult) < 0
}
return minTicket
func (ts *TipSet) MinTicket() *Ticket {
b := ts.MinTicketBlock()
return b.Tickets[len(b.Tickets)-1]
}
func (ts *TipSet) MinTimestamp() uint64 {
@ -120,3 +114,17 @@ func (ts *TipSet) MinTimestamp() uint64 {
}
return minTs
}
func (ts *TipSet) MinTicketBlock() *BlockHeader {
blks := ts.Blocks()
min := blks[0]
for _, b := range blks[1:] {
if b.LastTicket().Less(min.LastTicket()) {
min = b
}
}
return min
}

View File

@ -454,6 +454,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet,
}, nil
}
func (vm *VM) SetBlockMiner(m address.Address) {
vm.blockMiner = m
}
func (vm *VM) ActorBalance(addr address.Address) (types.BigInt, aerrors.ActorError) {
act, err := vm.cstate.GetActor(addr)
if err != nil {

View File

@ -143,7 +143,7 @@ func configureStorageMiner(ctx context.Context, api api.FullNode, addr address.A
}
// This really just needs to be an api call at this point...
recp, err := api.ChainCall(ctx, &types.Message{
recp, err := api.StateCall(ctx, &types.Message{
To: addr,
From: addr,
Method: actors.MAMethods.GetWorkerAddr,

2
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/gorilla/websocket v1.4.0
github.com/ipfs/go-bitswap v0.1.8
github.com/ipfs/go-block-format v0.0.2
github.com/ipfs/go-blockservice v0.1.2
github.com/ipfs/go-blockservice v0.1.3-0.20190908200855-f22eea50656c
github.com/ipfs/go-car v0.0.0-20190823083746-79984a8632b4
github.com/ipfs/go-cid v0.0.3
github.com/ipfs/go-datastore v0.1.0

2
go.sum
View File

@ -148,6 +148,8 @@ github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJ
github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M=
github.com/ipfs/go-blockservice v0.1.2 h1:fqFeeu1EG0lGVrqUo+BVJv7LZV31I4ZsyNthCOMAJRc=
github.com/ipfs/go-blockservice v0.1.2/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I=
github.com/ipfs/go-blockservice v0.1.3-0.20190908200855-f22eea50656c h1:lN5IQA07VtLiTLAp/Scezp1ljFhXErC6yq4O1cu+yJ0=
github.com/ipfs/go-blockservice v0.1.3-0.20190908200855-f22eea50656c/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I=
github.com/ipfs/go-car v0.0.0-20190823083746-79984a8632b4 h1:qYLz/x/d1SOiiFGS8dwCBCFJ5Oh64Y8HMBrS+MbaU8c=
github.com/ipfs/go-car v0.0.0-20190823083746-79984a8632b4/go.mod h1:NSSM0pxlhej9rSFXQmB/lDru7TYNoDjKgmvqzlsd06Y=
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=

View File

@ -2,8 +2,6 @@ package miner
import (
"context"
"crypto/sha256"
"math/big"
"sync"
"time"
@ -200,7 +198,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*chain.BlockMsg,
return nil, errors.Wrap(err, "scratching ticket failed")
}
win, proof, err := m.isWinnerNextRound(ctx, base)
win, proof, err := gen.IsRoundWinner(ctx, base.ts, base.tickets, m.addresses[0], &m.api)
if err != nil {
return nil, errors.Wrap(err, "failed to check if we win next round")
}
@ -234,7 +232,7 @@ func (m *Miner) computeVRF(ctx context.Context, input []byte) ([]byte, error) {
}
func (m *Miner) getMinerWorker(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
ret, err := m.api.ChainCall(ctx, &types.Message{
ret, err := m.api.StateCall(ctx, &types.Message{
From: addr,
To: addr,
Method: actors.MAMethods.GetWorkerAddr,
@ -255,43 +253,6 @@ func (m *Miner) getMinerWorker(ctx context.Context, addr address.Address, ts *ty
return w, nil
}
func (m *Miner) isWinnerNextRound(ctx context.Context, base *MiningBase) (bool, types.ElectionProof, error) {
r, err := m.api.ChainGetRandomness(context.TODO(), base.ts)
if err != nil {
return false, nil, err
}
vrfout, err := m.computeVRF(ctx, r)
if err != nil {
return false, nil, xerrors.Errorf("failed to compute VRF: %w", err)
}
pow, err := m.api.StateMinerPower(ctx, m.addresses[0], base.ts)
if err != nil {
return false, nil, xerrors.Errorf("failed to check power: %w", err)
}
return powerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil
}
func powerCmp(vrfout []byte, mpow, totpow types.BigInt) bool {
/*
Need to check that
h(vrfout) / 2^256 < minerPower / totalPower
*/
h := sha256.Sum256(vrfout)
// 2^256
rden := types.BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)}
top := types.BigMul(rden, mpow)
out := types.BigDiv(top, totpow)
return types.BigCmp(types.BigFromBytes(h[:]), out) < 0
}
func (m *Miner) runVDF(ctx context.Context, input []byte) ([]byte, []byte, error) {
select {
case <-ctx.Done():

View File

@ -20,6 +20,7 @@ import (
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/deals"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/wallet"
@ -201,6 +202,7 @@ func Online() Option {
Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages),
Override(new(*store.ChainStore), modules.ChainStore),
Override(new(*stmgr.StateManager), stmgr.NewStateManager),
Override(new(*wallet.Wallet), wallet.NewWallet),
Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker),

View File

@ -5,17 +5,11 @@ import (
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/gen"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"github.com/filecoin-project/go-lotus/lib/bufbstore"
"golang.org/x/xerrors"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-hamt-ipld"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"go.uber.org/fx"
)
@ -51,9 +45,8 @@ func (a *ChainAPI) ChainHead(context.Context) (*types.TipSet, error) {
return a.Chain.GetHeaviestTipSet(), nil
}
func (a *ChainAPI) ChainGetRandomness(ctx context.Context, pts *types.TipSet) ([]byte, error) {
// TODO: this needs to look back in the chain for the right random beacon value
return []byte("foo bar random"), nil
func (a *ChainAPI) ChainGetRandomness(ctx context.Context, pts *types.TipSet, tickets []*types.Ticket, lb int) ([]byte, error) {
return a.Chain.GetRandomness(ctx, pts, tickets, lb)
}
func (a *ChainAPI) ChainWaitMsg(ctx context.Context, msg cid.Cid) (*api.MsgWait, error) {
@ -113,72 +106,3 @@ func (a *ChainAPI) ChainGetBlockReceipts(ctx context.Context, bcid cid.Cid) ([]*
return out, nil
}
func (a *ChainAPI) ChainCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
return vm.Call(ctx, a.Chain, msg, ts)
}
func (a *ChainAPI) stateForTs(ts *types.TipSet) (*state.StateTree, error) {
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
st, err := a.Chain.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore())
cst := hamt.CSTFromBstore(buf)
return state.LoadStateTree(cst, st)
}
func (a *ChainAPI) ChainGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
return state.GetActor(actor)
}
func (a *ChainAPI) ChainReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*api.ActorState, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
blk, err := state.Store.Blocks.GetBlock(ctx, act.Head)
if err != nil {
return nil, err
}
oif, err := vm.DumpActorState(act.Code, blk.RawData())
if err != nil {
return nil, err
}
return &api.ActorState{
Balance: act.Balance,
State: oif,
}, nil
}
// This is on ChainAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
func (a *ChainAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) {
fblk, err := gen.MinerCreateBlock(ctx, a.Chain, a.Wallet, addr, parents, tickets, proof, msgs, ts)
if err != nil {
return nil, err
}
var out chain.BlockMsg
out.Header = fblk.Header
for _, msg := range fblk.BlsMessages {
out.BlsMessages = append(out.BlsMessages, msg.Cid())
}
for _, msg := range fblk.SecpkMessages {
out.SecpkMessages = append(out.SecpkMessages, msg.Cid())
}
return &out, nil
}

View File

@ -35,6 +35,7 @@ type ClientAPI struct {
fx.In
ChainAPI
StateAPI
WalletAPI
PaychAPI
@ -62,7 +63,7 @@ func (a *ClientAPI) ClientStartDeal(ctx context.Context, data cid.Cid, miner add
Method: actors.MAMethods.GetPeerID,
}
r, err := a.ChainCall(ctx, msg, nil)
r, err := a.StateCall(ctx, msg, nil)
if err != nil {
return nil, err
}

View File

@ -3,16 +3,22 @@ package full
import (
"context"
"fmt"
"strconv"
"github.com/filecoin-project/go-lotus/chain"
"github.com/filecoin-project/go-lotus/chain/gen"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"github.com/filecoin-project/go-lotus/chain/wallet"
"github.com/filecoin-project/go-lotus/lib/bufbstore"
"golang.org/x/xerrors"
"strconv"
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/ipfs/go-hamt-ipld"
cbor "github.com/ipfs/go-ipld-cbor"
@ -22,18 +28,23 @@ import (
type StateAPI struct {
fx.In
Chain *store.ChainStore
// TODO: the wallet here is only needed because we have the MinerCreateBlock
// API attached to the state API. It probably should live somewhere better
Wallet *wallet.Wallet
StateManager *stmgr.StateManager
Chain *store.ChainStore
}
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) {
ts := a.Chain.GetHeaviestTipSet()
ts := a.StateManager.ChainStore().GetHeaviestTipSet()
stc, err := a.Chain.TipSetState(ts.Cids())
stc, err := a.StateManager.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(a.Chain.Blockstore())
cst := hamt.CSTFromBstore(a.StateManager.ChainStore().Blockstore())
st, err := state.LoadStateTree(cst, stc)
if err != nil {
@ -86,7 +97,7 @@ func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address)
func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) {
ts := a.Chain.GetHeaviestTipSet()
stc, err := a.Chain.TipSetState(ts.Cids())
stc, err := a.StateManager.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
@ -142,47 +153,104 @@ func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Addres
}
func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, ts *types.TipSet) (api.MinerPower, error) {
var err error
enc, err := actors.SerializeParams(&actors.PowerLookupParams{maddr})
mpow, tpow, err := stmgr.GetPower(ctx, a.StateManager, ts, maddr)
if err != nil {
return api.MinerPower{}, err
}
var mpow types.BigInt
if maddr != address.Undef {
ret, err := vm.Call(ctx, a.Chain, &types.Message{
From: maddr,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.PowerLookup,
Params: enc,
}, ts)
if err != nil {
return api.MinerPower{}, xerrors.Errorf("failed to get miner power from chain: %w", err)
}
if ret.ExitCode != 0 {
return api.MinerPower{}, xerrors.Errorf("failed to get miner power from chain (exit code %d)", ret.ExitCode)
}
mpow = types.BigFromBytes(ret.Return)
}
ret, err := vm.Call(ctx, a.Chain, &types.Message{
From: actors.StorageMarketAddress,
To: actors.StorageMarketAddress,
Method: actors.SMAMethods.GetTotalStorage,
}, ts)
if err != nil {
return api.MinerPower{}, xerrors.Errorf("failed to get total power from chain: %w", err)
}
if ret.ExitCode != 0 {
return api.MinerPower{}, xerrors.Errorf("failed to get total power from chain (exit code %d)", ret.ExitCode)
}
tpow := types.BigFromBytes(ret.Return)
return api.MinerPower{
MinerPower: mpow,
TotalPower: tpow,
}, nil
}
func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) {
ret, err := a.StateManager.Call(ctx, &types.Message{
From: m,
To: m,
Method: actors.MAMethods.GetWorkerAddr,
}, ts)
if err != nil {
return address.Undef, xerrors.Errorf("failed to get miner worker addr: %w", err)
}
if ret.ExitCode != 0 {
return address.Undef, xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode)
}
w, err := address.NewFromBytes(ret.Return)
if err != nil {
return address.Undef, xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err)
}
return w, nil
}
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) {
return a.StateManager.Call(ctx, msg, ts)
}
func (a *StateAPI) stateForTs(ts *types.TipSet) (*state.StateTree, error) {
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
st, err := a.StateManager.TipSetState(ts.Cids())
if err != nil {
return nil, err
}
buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore())
cst := hamt.CSTFromBstore(buf)
return state.LoadStateTree(cst, st)
}
func (a *StateAPI) StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
return state.GetActor(actor)
}
func (a *StateAPI) StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*api.ActorState, error) {
state, err := a.stateForTs(ts)
if err != nil {
return nil, err
}
blk, err := state.Store.Blocks.GetBlock(ctx, act.Head)
if err != nil {
return nil, err
}
oif, err := vm.DumpActorState(act.Code, blk.RawData())
if err != nil {
return nil, err
}
return &api.ActorState{
Balance: act.Balance,
State: oif,
}, nil
}
// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
func (a *StateAPI) MinerCreateBlock(ctx context.Context, addr address.Address, parents *types.TipSet, tickets []*types.Ticket, proof types.ElectionProof, msgs []*types.SignedMessage, ts uint64) (*chain.BlockMsg, error) {
fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, addr, parents, tickets, proof, msgs, ts)
if err != nil {
return nil, err
}
var out chain.BlockMsg
out.Header = fblk.Header
for _, msg := range fblk.BlsMessages {
out.BlsMessages = append(out.BlsMessages, msg.Cid())
}
for _, msg := range fblk.SecpkMessages {
out.SecpkMessages = append(out.SecpkMessages, msg.Cid())
}
return &out, nil
}

View File

@ -4,7 +4,7 @@ import (
"context"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/wallet"
@ -15,8 +15,8 @@ import (
type WalletAPI struct {
fx.In
Chain *store.ChainStore
Wallet *wallet.Wallet
StateManager *stmgr.StateManager
Wallet *wallet.Wallet
}
func (a *WalletAPI) WalletNew(ctx context.Context, typ string) (address.Address, error) {
@ -32,7 +32,7 @@ func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) {
}
func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) {
return a.Chain.GetBalance(addr)
return a.StateManager.GetBalance(addr)
}
func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*types.Signature, error) {

View File

@ -1,7 +1,7 @@
package modules
import (
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/node/modules/dtypes"
"github.com/filecoin-project/go-lotus/paych"
)
@ -10,6 +10,6 @@ func PaychStore(ds dtypes.MetadataDS) *paych.Store {
return paych.NewStore(ds)
}
func PaymentChannelManager(chain *store.ChainStore, store *paych.Store) (*paych.Manager, error) {
return paych.NewManager(chain, store), nil
func PaymentChannelManager(sm *stmgr.StateManager, store *paych.Store) (*paych.Manager, error) {
return paych.NewManager(sm, store), nil
}

View File

@ -12,6 +12,7 @@ import (
offline "github.com/ipfs/go-ipfs-exchange-offline"
logging "github.com/ipfs/go-log"
"github.com/ipfs/go-merkledag"
peer "github.com/libp2p/go-libp2p-peer"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/gen"
@ -34,8 +35,9 @@ func MakeGenesisMem(out io.Writer) func(bs dtypes.ChainBlockstore, w *wallet.Wal
}
gmc := &gen.GenMinerCfg{
Owner: w,
Worker: w,
Owners: []address.Address{w},
Workers: []address.Address{w},
PeerIDs: []peer.ID{"peerID 1"},
}
alloc := map[address.Address]types.BigInt{
w: types.NewInt(100000),
@ -68,8 +70,9 @@ func MakeGenesis(outFile string) func(bs dtypes.ChainBlockstore, w *wallet.Walle
}
gmc := &gen.GenMinerCfg{
Owner: minerAddr,
Worker: minerAddr,
Owners: []address.Address{minerAddr},
Workers: []address.Address{minerAddr},
PeerIDs: []peer.ID{"peer ID 1"},
}
addrs := map[address.Address]types.BigInt{
@ -81,7 +84,7 @@ func MakeGenesis(outFile string) func(bs dtypes.ChainBlockstore, w *wallet.Walle
return nil, err
}
fmt.Println("GENESIS MINER ADDRESS: ", gmc.MinerAddr.String())
fmt.Println("GENESIS MINER ADDRESS: ", gmc.MinerAddrs[0].String())
f, err := os.OpenFile(outFile, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {

View File

@ -4,28 +4,25 @@ import (
"context"
"fmt"
hamt "github.com/ipfs/go-hamt-ipld"
logging "github.com/ipfs/go-log"
"github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
)
var log = logging.Logger("paych")
type Manager struct {
chain *store.ChainStore
store *Store
sm *stmgr.StateManager
}
func NewManager(chain *store.ChainStore, pchstore *Store) *Manager {
func NewManager(sm *stmgr.StateManager, pchstore *Store) *Manager {
return &Manager{
chain: chain,
store: pchstore,
sm: sm,
}
}
@ -148,7 +145,7 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
return false, err
}
ret, err := vm.Call(ctx, pm.chain, &types.Message{
ret, err := pm.sm.Call(ctx, &types.Message{
From: owner,
To: ch,
Method: actors.PCAMethods.UpdateChannelState,
@ -166,24 +163,9 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
}
func (pm *Manager) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *actors.PaymentChannelActorState, error) {
st, err := pm.chain.TipSetState(pm.chain.GetHeaviestTipSet().Cids())
if err != nil {
return nil, nil, err
}
cst := hamt.CSTFromBstore(pm.chain.Blockstore())
tree, err := state.LoadStateTree(cst, st)
if err != nil {
return nil, nil, err
}
act, err := tree.GetActor(ch)
if err != nil {
return nil, nil, err
}
var pcast actors.PaymentChannelActorState
if err := cst.Get(ctx, act.Head, &pcast); err != nil {
act, err := pm.sm.LoadActorState(ctx, ch, &pcast)
if err != nil {
return nil, nil, err
}
@ -191,7 +173,7 @@ func (pm *Manager) loadPaychState(ctx context.Context, ch address.Address) (*typ
}
func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (address.Address, error) {
ret, err := vm.Call(ctx, pm.chain, &types.Message{
ret, err := pm.sm.Call(ctx, &types.Message{
From: ch,
To: ch,
Method: actors.PCAMethods.GetOwner,

View File

@ -41,7 +41,7 @@ type storageMinerApi interface {
//ReadState(ctx context.Context, addr address.Address) (????, error)
// Call a read only method on actors (no interaction with the chain required)
ChainCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error)
StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error)
MpoolPush(context.Context, *types.SignedMessage) error
MpoolGetNonce(context.Context, address.Address) (uint64, error)
@ -201,7 +201,7 @@ func (m *Miner) getWorkerAddr(ctx context.Context) (address.Address, error) {
Params: actors.EmptyStructCBOR,
}
recpt, err := m.api.ChainCall(ctx, msg, nil)
recpt, err := m.api.StateCall(ctx, msg, nil)
if err != nil {
return address.Undef, errors.Wrapf(err, "calling getWorker(%s)", m.maddr)
}