switch to parent state roots

This commit is contained in:
whyrusleeping 2019-09-27 16:55:15 -07:00
parent 6a729263a4
commit 1419031f1e
16 changed files with 206 additions and 192 deletions

View File

@ -145,7 +145,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) {
func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader { func fakeBlock(t *testing.T, minerAddr address.Address, ts uint64) *types.BlockHeader {
c := fakeCid(t, 1) 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}} return &types.BlockHeader{Height: 5, Miner: minerAddr, Timestamp: ts, ParentStateRoot: c, Messages: c, ParentMessageReceipts: c, BLSAggregate: types.Signature{Type: types.KTBLS}}
} }
func fakeCid(t *testing.T, s int) cid.Cid { func fakeCid(t *testing.T, s int) cid.Cid {

View File

@ -143,7 +143,7 @@ func (h *Handler) saveAsk(a *types.SignedStorageAsk) error {
} }
func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error { func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error {
tss, err := c.sm.TipSetState(c.sm.ChainStore().GetHeaviestTipSet().Cids()) tss, _, err := c.sm.TipSetState(c.sm.ChainStore().GetHeaviestTipSet().Cids())
if err != nil { if err != nil {
return xerrors.Errorf("failed to get tipsetstate to query for miner worker: %w", err) return xerrors.Errorf("failed to get tipsetstate to query for miner worker: %w", err)
} }

View File

@ -3,11 +3,12 @@ package events
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain/store"
"testing" "testing"
"time" "time"
"github.com/filecoin-project/go-lotus/api"
"github.com/filecoin-project/go-lotus/chain/store"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -48,9 +49,9 @@ func makeTs(t *testing.T, h uint64, msgcid cid.Cid) *types.TipSet {
{ {
Height: h, Height: h,
StateRoot: dummyCid, ParentStateRoot: dummyCid,
Messages: msgcid, Messages: msgcid,
MessageReceipts: dummyCid, ParentMessageReceipts: dummyCid,
}, },
}) })
@ -608,5 +609,4 @@ func TestCalledOrder(t *testing.T) {
}) })
fcs.advance(9, 1, nil) fcs.advance(9, 1, nil)
} }

View File

@ -201,7 +201,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, m address.Address, ticks
lastTicket = ticks[len(ticks)-1] lastTicket = ticks[len(ticks)-1]
} }
st, err := cg.sm.TipSetState(pts.Cids()) st, _, err := cg.sm.TipSetState(pts.Cids())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -376,7 +376,7 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t
} }
func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) { func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) {
st, err := mca.sm.TipSetState(ts.Cids()) st, _, err := mca.sm.TipSetState(ts.Cids())
if err != nil { if err != nil {
return address.Undef, err return address.Undef, err
} }

View File

@ -20,7 +20,7 @@ import (
) )
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) { 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()) st, recpts, err := sm.TipSetState(parents.Cids())
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to load tipset state") return nil, errors.Wrap(err, "failed to load tipset state")
} }
@ -53,12 +53,14 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
} }
next := &types.BlockHeader{ next := &types.BlockHeader{
Miner: miner, Miner: miner,
Parents: parents.Cids(), Parents: parents.Cids(),
Tickets: tickets, Tickets: tickets,
Height: height, Height: height,
Timestamp: timestamp, Timestamp: timestamp,
ElectionProof: proof, ElectionProof: proof,
ParentStateRoot: st,
ParentMessageReceipts: recpts,
} }
var blsMessages []*types.Message var blsMessages []*types.Message
@ -83,24 +85,6 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
} }
} }
var receipts []cbg.CBORMarshaler
for _, msg := range blsMessages {
rec, err := vmi.ApplyMessage(ctx, msg)
if err != nil {
return nil, errors.Wrap(err, "apply message failure")
}
receipts = append(receipts, &rec.MessageReceipt)
}
for _, msg := range secpkMessages {
rec, err := vmi.ApplyMessage(ctx, &msg.Message)
if err != nil {
return nil, errors.Wrap(err, "apply message failure")
}
receipts = append(receipts, &rec.MessageReceipt)
}
bs := amt.WrapBlockstore(sm.ChainStore().Blockstore()) bs := amt.WrapBlockstore(sm.ChainStore().Blockstore())
blsmsgroot, err := amt.FromArray(bs, toIfArr(blsMsgCids)) blsmsgroot, err := amt.FromArray(bs, toIfArr(blsMsgCids))
if err != nil { if err != nil {
@ -120,24 +104,12 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
} }
next.Messages = mmcid next.Messages = mmcid
rectroot, err := amt.FromArray(bs, receipts)
if err != nil {
return nil, xerrors.Errorf("failed to build receipts amt: %w", err)
}
next.MessageReceipts = rectroot
stateRoot, err := vmi.Flush(context.TODO())
if err != nil {
return nil, errors.Wrap(err, "flushing state tree failed")
}
aggSig, err := aggregateSignatures(blsSigs) aggSig, err := aggregateSignatures(blsSigs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
next.BLSAggregate = aggSig next.BLSAggregate = aggSig
next.StateRoot = stateRoot
pweight := sm.ChainStore().Weight(parents) pweight := sm.ChainStore().Weight(parents)
next.ParentWeight = types.NewInt(pweight) next.ParentWeight = types.NewInt(pweight)

View File

@ -335,18 +335,18 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B
} }
b := &types.BlockHeader{ b := &types.BlockHeader{
Miner: actors.InitActorAddress, Miner: actors.InitActorAddress,
Tickets: []*types.Ticket{genesisticket}, Tickets: []*types.Ticket{genesisticket},
ElectionProof: []byte("the Genesis block"), ElectionProof: []byte("the Genesis block"),
Parents: []cid.Cid{}, Parents: []cid.Cid{},
Height: 0, Height: 0,
ParentWeight: types.NewInt(0), ParentWeight: types.NewInt(0),
StateRoot: stateroot, ParentStateRoot: stateroot,
Messages: mmb.Cid(), Messages: mmb.Cid(),
MessageReceipts: emptyroot, ParentMessageReceipts: emptyroot,
BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")}, BLSAggregate: types.Signature{Type: types.KTBLS, Data: []byte("signatureeee")},
BlockSig: types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")}, BlockSig: types.Signature{Type: types.KTBLS, Data: []byte("block signatureeee")},
Timestamp: ts, Timestamp: ts,
} }
sb, err := b.ToStorageBlock() sb, err := b.ToStorageBlock()

View File

@ -53,7 +53,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.
ts = sm.cs.GetHeaviestTipSet() ts = sm.cs.GetHeaviestTipSet()
} }
state, err := sm.TipSetState(ts.Cids()) state, _, err := sm.TipSetState(ts.Cids())
if err != nil { if err != nil {
return nil, xerrors.Errorf("getting tipset state: %w", err) return nil, xerrors.Errorf("getting tipset state: %w", err)
} }
@ -69,7 +69,7 @@ func (sm *StateManager) Replay(ctx context.Context, ts *types.TipSet, mcid cid.C
var outm *types.Message var outm *types.Message
var outr *vm.ApplyRet var outr *vm.ApplyRet
_, err := sm.computeTipSetState(ctx, ts.Blocks(), func(c cid.Cid, m *types.Message, ret *vm.ApplyRet) error { _, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(c cid.Cid, m *types.Message, ret *vm.ApplyRet) error {
if c == mcid { if c == mcid {
outm = m outm = m
outr = ret outr = ret

View File

@ -4,11 +4,13 @@ import (
"context" "context"
"sync" "sync"
amt "github.com/filecoin-project/go-amt-ipld"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state" "github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm" "github.com/filecoin-project/go-lotus/chain/vm"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
@ -21,14 +23,14 @@ var log = logging.Logger("statemgr")
type StateManager struct { type StateManager struct {
cs *store.ChainStore cs *store.ChainStore
stCache map[string]cid.Cid stCache map[string][]cid.Cid
stlk sync.Mutex stlk sync.Mutex
} }
func NewStateManager(cs *store.ChainStore) *StateManager { func NewStateManager(cs *store.ChainStore) *StateManager {
return &StateManager{ return &StateManager{
cs: cs, cs: cs,
stCache: make(map[string]cid.Cid), stCache: make(map[string][]cid.Cid),
} }
} }
@ -40,7 +42,7 @@ func cidsToKey(cids []cid.Cid) string {
return out return out
} }
func (sm *StateManager) TipSetState(cids []cid.Cid) (cid.Cid, error) { func (sm *StateManager) TipSetState(cids []cid.Cid) (cid.Cid, cid.Cid, error) {
ctx := context.TODO() ctx := context.TODO()
ck := cidsToKey(cids) ck := cidsToKey(cids)
@ -48,34 +50,32 @@ func (sm *StateManager) TipSetState(cids []cid.Cid) (cid.Cid, error) {
cached, ok := sm.stCache[ck] cached, ok := sm.stCache[ck]
sm.stlk.Unlock() sm.stlk.Unlock()
if ok { if ok {
return cached, nil return cached[0], cached[1], nil
} }
ts, err := sm.cs.LoadTipSet(cids) ts, err := sm.cs.LoadTipSet(cids)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, cid.Undef, err
} }
out, err := sm.computeTipSetState(ctx, ts.Blocks(), nil) st, rec, err := sm.computeTipSetState(ctx, ts.Blocks(), nil)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, cid.Undef, err
} }
sm.stlk.Lock() sm.stlk.Lock()
sm.stCache[ck] = out sm.stCache[ck] = []cid.Cid{st, rec}
sm.stlk.Unlock() sm.stlk.Unlock()
return out, nil return st, rec, nil
} }
func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.BlockHeader, cb func(cid.Cid, *types.Message, *vm.ApplyRet) error) (cid.Cid, error) { type ChainMsg interface {
if len(blks) == 1 && cb == nil { Cid() cid.Cid
return blks[0].StateRoot, nil VMMessage() *types.Message
} }
pstate, err := sm.TipSetState(blks[0].Parents) func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.BlockHeader, cb func(cid.Cid, *types.Message, *vm.ApplyRet) error) (cid.Cid, cid.Cid, error) {
if err != nil { pstate := blks[0].ParentStateRoot
return cid.Undef, xerrors.Errorf("recursive TipSetState failed: %w", err)
}
cids := make([]cid.Cid, len(blks)) cids := make([]cid.Cid, len(blks))
for i, v := range blks { for i, v := range blks {
@ -86,56 +86,94 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs) vmi, err := vm.NewVM(pstate, blks[0].Height, r, address.Undef, sm.cs)
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
} }
applied := make(map[cid.Cid]bool) /* TODO: apply mining reward
netbalance, err := vmi.ActorBalance(actors.NetworkAddress)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to get network actor balance: %w", err)
}
vm.MiningRewardForBlock(netbalance)
*/
applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt)
preloadAddr := func(a address.Address) error {
if _, ok := applied[a]; !ok {
act, err := vmi.StateTree().GetActor(a)
if err != nil {
return err
}
applied[a] = act.Nonce
balances[a] = act.Balance
}
return nil
}
var receipts []cbg.CBORMarshaler
for _, b := range blks { for _, b := range blks {
vmi.SetBlockMiner(b.Miner) vmi.SetBlockMiner(b.Miner)
bms, sms, err := sm.cs.MessagesForBlock(b) bms, sms, err := sm.cs.MessagesForBlock(b)
if err != nil { if err != nil {
return cid.Undef, xerrors.Errorf("failed to get messages for block: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("failed to get messages for block: %w", err)
} }
cmsgs := make([]ChainMsg, 0, len(bms)+len(sms))
for _, m := range bms { for _, m := range bms {
if applied[m.Cid()] { cmsgs = append(cmsgs, m)
}
for _, sm := range sms {
cmsgs = append(cmsgs, sm)
}
for _, cm := range cmsgs {
m := cm.VMMessage()
if err := preloadAddr(m.From); err != nil {
return cid.Undef, cid.Undef, err
}
if applied[m.From] != m.Nonce {
continue continue
} }
applied[m.Cid()] = true applied[m.From]++
if balances[m.From].LessThan(m.RequiredFunds()) {
continue
}
balances[m.From] = types.BigSub(balances[m.From], m.RequiredFunds())
r, err := vmi.ApplyMessage(ctx, m) r, err := vmi.ApplyMessage(ctx, m)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, cid.Undef, err
} }
receipts = append(receipts, &r.MessageReceipt)
if cb != nil { if cb != nil {
if err := cb(m.Cid(), m, r); err != nil { if err := cb(cm.Cid(), m, r); err != nil {
return cid.Undef, err return cid.Undef, cid.Undef, err
}
}
}
for _, sm := range sms {
if applied[sm.Cid()] {
continue
}
applied[sm.Cid()] = true
r, err := vmi.ApplyMessage(ctx, &sm.Message)
if err != nil {
return cid.Undef, err
}
if cb != nil {
if err := cb(sm.Cid(), &sm.Message, r); err != nil {
return cid.Undef, err
} }
} }
} }
} }
return vmi.Flush(ctx) bs := amt.WrapBlockstore(sm.cs.Blockstore())
rectroot, err := amt.FromArray(bs, receipts)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err)
}
st, err := vmi.Flush(ctx)
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("vm flush failed: %w", err)
}
return st, rectroot, nil
} }
func (sm *StateManager) GetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { func (sm *StateManager) GetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
@ -143,7 +181,7 @@ func (sm *StateManager) GetActor(addr address.Address, ts *types.TipSet) (*types
ts = sm.cs.GetHeaviestTipSet() ts = sm.cs.GetHeaviestTipSet()
} }
stcid, err := sm.TipSetState(ts.Cids()) stcid, _, err := sm.TipSetState(ts.Cids())
if err != nil { if err != nil {
return nil, xerrors.Errorf("tipset state: %w", err) return nil, xerrors.Errorf("tipset state: %w", err)
} }

View File

@ -551,7 +551,7 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message,
func (cs *ChainStore) GetReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) { func (cs *ChainStore) GetReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) {
bs := amt.WrapBlockstore(cs.bs) bs := amt.WrapBlockstore(cs.bs)
a, err := amt.LoadAMT(bs, b.MessageReceipts) a, err := amt.LoadAMT(bs, b.ParentMessageReceipts)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "amt load") return nil, errors.Wrap(err, "amt load")
} }

View File

@ -10,15 +10,16 @@ import (
"github.com/filecoin-project/go-lotus/build" "github.com/filecoin-project/go-lotus/build"
"github.com/filecoin-project/go-lotus/chain/actors" "github.com/filecoin-project/go-lotus/chain/actors"
"github.com/filecoin-project/go-lotus/chain/address" "github.com/filecoin-project/go-lotus/chain/address"
"github.com/filecoin-project/go-lotus/chain/state"
"github.com/filecoin-project/go-lotus/chain/stmgr" "github.com/filecoin-project/go-lotus/chain/stmgr"
"github.com/filecoin-project/go-lotus/chain/store" "github.com/filecoin-project/go-lotus/chain/store"
"github.com/filecoin-project/go-lotus/chain/types" "github.com/filecoin-project/go-lotus/chain/types"
"github.com/filecoin-project/go-lotus/chain/vm"
"github.com/filecoin-project/go-lotus/lib/vdf" "github.com/filecoin-project/go-lotus/lib/vdf"
amt "github.com/filecoin-project/go-amt-ipld" amt "github.com/filecoin-project/go-amt-ipld"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
dstore "github.com/ipfs/go-datastore" dstore "github.com/ipfs/go-datastore"
hamt "github.com/ipfs/go-hamt-ipld"
bstore "github.com/ipfs/go-ipfs-blockstore" bstore "github.com/ipfs/go-ipfs-blockstore"
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
@ -380,11 +381,19 @@ func (syncer *Syncer) validateTickets(ctx context.Context, mworker address.Addre
// Should match up with 'Semantical Validation' in validation.md in the spec // Should match up with 'Semantical Validation' in validation.md in the spec
func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error { func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error {
h := b.Header h := b.Header
stateroot, err := syncer.sm.TipSetState(h.Parents) stateroot, precp, err := syncer.sm.TipSetState(h.Parents)
if err != nil { if err != nil {
return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err) return xerrors.Errorf("get tipsetstate(%d, %s) failed: %w", h.Height, h.Parents, err)
} }
if stateroot != h.ParentStateRoot {
return xerrors.Errorf("parent state root did not match computed state (%s != %s)", stateroot, h.ParentStateRoot)
}
if precp != h.ParentMessageReceipts {
return xerrors.Errorf("parent receipts root did not match computed value (%s != %s)", precp, h.ParentMessageReceipts)
}
baseTs, err := syncer.store.LoadTipSet(h.Parents) baseTs, err := syncer.store.LoadTipSet(h.Parents)
if err != nil { if err != nil {
return xerrors.Errorf("load tipset failed: %w", err) return xerrors.Errorf("load tipset failed: %w", err)
@ -434,61 +443,48 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("miner created a block but was not a winner") return xerrors.Errorf("miner created a block but was not a winner")
} }
r := vm.NewChainRand(syncer.store, baseTs.Cids(), baseTs.Height(), h.Tickets) nonces := make(map[address.Address]uint64)
vmi, err := vm.NewVM(stateroot, h.Height, r, h.Miner, syncer.store) balances := make(map[address.Address]types.BigInt)
cst := hamt.CSTFromBstore(syncer.store.Blockstore())
st, err := state.LoadStateTree(cst, stateroot)
if err != nil { if err != nil {
return xerrors.Errorf("failed to instantiate VM: %w", err) return xerrors.Errorf("failed to load base state tree: %w", err)
} }
owner, err := stmgr.GetMinerOwner(ctx, syncer.sm, stateroot, b.Header.Miner) checkMsg := func(m *types.Message) error {
if err != nil { if _, ok := nonces[m.From]; !ok {
return xerrors.Errorf("getting miner owner for block miner failed: %w", err) act, err := st.GetActor(m.From)
} if err != nil {
networkBalance, err := vmi.ActorBalance(actors.NetworkAddress) return xerrors.Errorf("failed to get actor: %w", err)
if err != nil { }
return xerrors.Errorf("getting network balance") nonces[m.From] = act.Nonce
} balances[m.From] = act.Balance
if err := vmi.TransferFunds(actors.NetworkAddress, owner,
vm.MiningReward(networkBalance)); err != nil {
return xerrors.Errorf("fund transfer failed: %w", err)
}
var receipts []cbg.CBORMarshaler
for i, m := range b.BlsMessages {
receipt, err := vmi.ApplyMessage(ctx, m)
if err != nil {
return xerrors.Errorf("failed executing bls message %d in block %s: %w", i, b.Header.Cid(), err)
} }
receipts = append(receipts, &receipt.MessageReceipt) if nonces[m.From] != m.Nonce {
return xerrors.Errorf("wrong nonce")
}
nonces[m.From]++
if balances[m.From].LessThan(m.RequiredFunds()) {
return xerrors.Errorf("not enough funds for message execution")
}
balances[m.From] = types.BigSub(balances[m.From], m.RequiredFunds())
return nil
}
for i, m := range b.BlsMessages {
if err := checkMsg(m); err != nil {
xerrors.Errorf("block had invalid bls message at index %d: %w", i, err)
}
} }
for i, m := range b.SecpkMessages { for i, m := range b.SecpkMessages {
receipt, err := vmi.ApplyMessage(ctx, &m.Message) if err := checkMsg(&m.Message); err != nil {
if err != nil { xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
return xerrors.Errorf("failed executing secpk message %d in block %s: %w", i, b.Header.Cid(), err)
} }
receipts = append(receipts, &receipt.MessageReceipt)
}
bs := amt.WrapBlockstore(syncer.store.Blockstore())
recptRoot, err := amt.FromArray(bs, receipts)
if err != nil {
return xerrors.Errorf("building receipts amt failed: %w", err)
}
if recptRoot != b.Header.MessageReceipts {
return fmt.Errorf("receipts mismatched")
}
final, err := vmi.Flush(context.TODO())
if err != nil {
return xerrors.Errorf("failed to flush VM state: %w", err)
}
if b.Header.StateRoot != final {
return fmt.Errorf("final state root does not match block")
} }
return nil return nil

View File

@ -34,14 +34,14 @@ type BlockHeader struct {
Height uint64 Height uint64
StateRoot cid.Cid ParentStateRoot cid.Cid
ParentMessageReceipts cid.Cid
Messages cid.Cid Messages cid.Cid
BLSAggregate Signature BLSAggregate Signature
MessageReceipts cid.Cid
Timestamp uint64 Timestamp uint64
BlockSig Signature BlockSig Signature

View File

@ -32,14 +32,14 @@ func testBlockHeader(t testing.TB) *BlockHeader {
VDFProof: []byte("vrf proof"), VDFProof: []byte("vrf proof"),
}, },
}, },
Parents: []cid.Cid{c, c}, Parents: []cid.Cid{c, c},
MessageReceipts: c, ParentMessageReceipts: c,
BLSAggregate: Signature{Type: KTBLS, Data: []byte("boo! im a signature")}, BLSAggregate: Signature{Type: KTBLS, Data: []byte("boo! im a signature")},
ParentWeight: NewInt(123125126212), ParentWeight: NewInt(123125126212),
Messages: c, Messages: c,
Height: 85919298723, Height: 85919298723,
StateRoot: c, ParentStateRoot: c,
BlockSig: Signature{Type: KTBLS, Data: []byte("boo! im a signature")}, BlockSig: Signature{Type: KTBLS, Data: []byte("boo! im a signature")},
} }
} }

View File

@ -5,7 +5,7 @@ import (
"io" "io"
"math" "math"
"github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors" xerrors "golang.org/x/xerrors"
) )
@ -66,10 +66,16 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.t.StateRoot (cid.Cid) // t.t.ParentStateRoot (cid.Cid)
if err := cbg.WriteCid(w, t.StateRoot); err != nil { if err := cbg.WriteCid(w, t.ParentStateRoot); err != nil {
return xerrors.Errorf("failed to write cid field t.StateRoot: %w", err) return xerrors.Errorf("failed to write cid field t.ParentStateRoot: %w", err)
}
// t.t.ParentMessageReceipts (cid.Cid)
if err := cbg.WriteCid(w, t.ParentMessageReceipts); err != nil {
return xerrors.Errorf("failed to write cid field t.ParentMessageReceipts: %w", err)
} }
// t.t.Messages (cid.Cid) // t.t.Messages (cid.Cid)
@ -83,12 +89,6 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.t.MessageReceipts (cid.Cid)
if err := cbg.WriteCid(w, t.MessageReceipts); err != nil {
return xerrors.Errorf("failed to write cid field t.MessageReceipts: %w", err)
}
// t.t.Timestamp (uint64) // t.t.Timestamp (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Timestamp)); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Timestamp)); err != nil {
return err return err
@ -212,16 +212,28 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("wrong type for uint64 field") return fmt.Errorf("wrong type for uint64 field")
} }
t.Height = extra t.Height = extra
// t.t.StateRoot (cid.Cid) // t.t.ParentStateRoot (cid.Cid)
{ {
c, err := cbg.ReadCid(br) c, err := cbg.ReadCid(br)
if err != nil { if err != nil {
return xerrors.Errorf("failed to read cid field t.StateRoot: %w", err) return xerrors.Errorf("failed to read cid field t.ParentStateRoot: %w", err)
} }
t.StateRoot = c t.ParentStateRoot = c
}
// t.t.ParentMessageReceipts (cid.Cid)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.ParentMessageReceipts: %w", err)
}
t.ParentMessageReceipts = c
} }
// t.t.Messages (cid.Cid) // t.t.Messages (cid.Cid)
@ -244,18 +256,6 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
return err return err
} }
}
// t.t.MessageReceipts (cid.Cid)
{
c, err := cbg.ReadCid(br)
if err != nil {
return xerrors.Errorf("failed to read cid field t.MessageReceipts: %w", err)
}
t.MessageReceipts = c
} }
// t.t.Timestamp (uint64) // t.t.Timestamp (uint64)

View File

@ -73,3 +73,7 @@ func (m *Message) RequiredFunds() BigInt {
BigMul(m.GasPrice, m.GasLimit), BigMul(m.GasPrice, m.GasLimit),
) )
} }
func (m *Message) VMMessage() *Message {
return m
}

View File

@ -57,3 +57,7 @@ func (sm *SignedMessage) Serialize() ([]byte, error) {
} }
return buf.Bytes(), nil return buf.Bytes(), nil
} }
func (sm *SignedMessage) VMMessage() *Message {
return &sm.Message
}

View File

@ -134,7 +134,7 @@ func (a *StateAPI) stateForTs(ts *types.TipSet) (*state.StateTree, error) {
ts = a.Chain.GetHeaviestTipSet() ts = a.Chain.GetHeaviestTipSet()
} }
st, err := a.StateManager.TipSetState(ts.Cids()) st, _, err := a.StateManager.TipSetState(ts.Cids())
if err != nil { if err != nil {
return nil, err return nil, err
} }