Add new BlockMsgsForTipset()

This commit is contained in:
Aayush Rajasekaran 2020-08-08 21:37:49 -04:00
parent c72f853e09
commit 532c32a741
5 changed files with 78 additions and 59 deletions

View File

@ -196,7 +196,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, 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

@ -111,7 +111,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil return ts.Blocks()[0].ParentStateRoot, ts.Blocks()[0].ParentMessageReceipts, nil
} }
st, rec, err = sm.computeTipSetState(ctx, ts.Blocks(), nil) st, rec, err = sm.computeTipSetState(ctx, ts, nil)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, err return cid.Undef, cid.Undef, err
} }
@ -121,7 +121,7 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c
func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) { func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
var trace []*api.InvocResult var trace []*api.InvocResult
st, _, err := sm.computeTipSetState(ctx, ts.Blocks(), func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { st, _, err := sm.computeTipSetState(ctx, ts, func(mcid cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
ir := &api.InvocResult{ ir := &api.InvocResult{
Msg: msg, Msg: msg,
MsgRct: &ret.MessageReceipt, MsgRct: &ret.MessageReceipt,
@ -141,16 +141,9 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
return st, trace, nil return st, trace, nil
} }
type BlockMessages struct {
Miner address.Address
BlsMessages []types.ChainMsg
SecpkMessages []types.ChainMsg
WinCount int64
}
type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) { func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) {
vmopt := &vm.VMOpts{ vmopt := &vm.VMOpts{
StateBase: pstate, StateBase: pstate,
@ -311,10 +304,12 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
return st, rectroot, nil return st, rectroot, nil
} }
func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.BlockHeader, cb ExecCallback) (cid.Cid, cid.Cid, error) { func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet, cb ExecCallback) (cid.Cid, cid.Cid, error) {
ctx, span := trace.StartSpan(ctx, "computeTipSetState") ctx, span := trace.StartSpan(ctx, "computeTipSetState")
defer span.End() defer span.End()
blks := ts.Blocks()
for i := 0; i < len(blks); i++ { for i := 0; i < len(blks); i++ {
for j := i + 1; j < len(blks); j++ { for j := i + 1; j < len(blks); j++ {
if blks[i].Miner == blks[j].Miner { if blks[i].Miner == blks[j].Miner {
@ -343,30 +338,11 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
r := store.NewChainRand(sm.cs, cids, blks[0].Height) r := store.NewChainRand(sm.cs, cids, blks[0].Height)
var blkmsgs []BlockMessages blkmsgs, err := sm.cs.BlockMsgsForTipset(ts)
for _, b := range blks {
bms, sms, err := sm.cs.MessagesForBlock(b)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to get messages for block: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("getting block messages for tipset: %w", err)
} }
bm := BlockMessages{
Miner: b.Miner,
BlsMessages: make([]types.ChainMsg, 0, len(bms)),
SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
WinCount: b.ElectionProof.WinCount,
}
for _, m := range bms {
bm.BlsMessages = append(bm.BlsMessages, m)
}
for _, m := range sms {
bm.SecpkMessages = append(bm.SecpkMessages, m)
}
blkmsgs = append(blkmsgs, bm)
}
baseFee := blks[0].ParentBaseFee baseFee := blks[0].ParentBaseFee
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee) return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee)

View File

@ -707,9 +707,15 @@ func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) {
return cids, nil return cids, nil
} }
func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) { type BlockMessages struct {
Miner address.Address
BlsMessages []types.ChainMsg
SecpkMessages []types.ChainMsg
WinCount int64
}
func (cs *ChainStore) BlockMsgsForTipset(ts *types.TipSet) ([]BlockMessages, error) {
applied := make(map[address.Address]uint64) applied := make(map[address.Address]uint64)
balances := make(map[address.Address]types.BigInt)
cst := cbor.NewCborStore(cs.bs) cst := cbor.NewCborStore(cs.bs)
st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot) st, err := state.LoadStateTree(cst, ts.Blocks()[0].ParentStateRoot)
@ -725,43 +731,80 @@ func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, err
} }
applied[a] = act.Nonce applied[a] = act.Nonce
balances[a] = act.Balance
} }
return nil return nil
} }
var out []types.ChainMsg selectMsg := func(m *types.Message) (bool, error) {
if err := preloadAddr(m.From); err != nil {
return false, err
}
if applied[m.From] != m.Nonce {
return false, nil
}
applied[m.From]++
return true, nil
}
var out []BlockMessages
for _, b := range ts.Blocks() { for _, b := range ts.Blocks() {
bms, sms, err := cs.MessagesForBlock(b) bms, sms, err := cs.MessagesForBlock(b)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to get messages for block: %w", err) return nil, xerrors.Errorf("failed to get messages for block: %w", err)
} }
cmsgs := make([]types.ChainMsg, 0, len(bms)+len(sms)) bm := BlockMessages{
for _, m := range bms { Miner: b.Miner,
cmsgs = append(cmsgs, m) BlsMessages: make([]types.ChainMsg, 0, len(bms)),
} SecpkMessages: make([]types.ChainMsg, 0, len(sms)),
for _, sm := range sms { WinCount: b.ElectionProof.WinCount,
cmsgs = append(cmsgs, sm)
} }
for _, cm := range cmsgs { for _, bmsg := range bms {
m := cm.VMMessage() b, err := selectMsg(bmsg.VMMessage())
if err := preloadAddr(m.From); err != nil { if err != nil {
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
}
if b {
bm.BlsMessages = append(bm.BlsMessages, bmsg)
}
}
for _, smsg := range sms {
b, err := selectMsg(smsg.VMMessage())
if err != nil {
return nil, xerrors.Errorf("failed to decide whether to select message for block: %w", err)
}
if b {
bm.SecpkMessages = append(bm.SecpkMessages, smsg)
}
}
out = append(out, bm)
}
return out, nil
}
func (cs *ChainStore) MessagesForTipset(ts *types.TipSet) ([]types.ChainMsg, error) {
bmsgs, err := cs.BlockMsgsForTipset(ts)
if err != nil {
return nil, err return nil, err
} }
if applied[m.From] != m.Nonce { var out []types.ChainMsg
continue for _, bm := range bmsgs {
for _, blsm := range bm.BlsMessages {
out = append(out, blsm)
} }
applied[m.From]++
if balances[m.From].LessThan(m.RequiredFunds()) { for _, secm := range bm.SecpkMessages {
continue out = append(out, secm)
}
balances[m.From] = types.BigSub(balances[m.From], m.RequiredFunds())
out = append(out, cm)
} }
} }

View File

@ -547,7 +547,7 @@ func TestSyncFork(t *testing.T) {
phead() phead()
} }
// This message crafts a tipset with 2 blocks, A and B. // This test crafts a tipset with 2 blocks, A and B.
// A and B both include _different_ messages from sender X with nonce N (where N is the correct nonce for X). // A and B both include _different_ messages from sender X with nonce N (where N is the correct nonce for X).
// We can confirm that the state can be correctly computed, and that `MessagesForTipset` behaves as expected. // We can confirm that the state can be correctly computed, and that `MessagesForTipset` behaves as expected.
func TestDuplicateNonce(t *testing.T) { func TestDuplicateNonce(t *testing.T) {

View File

@ -71,9 +71,9 @@ func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.Bloc
cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls) cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls)
sm := stmgr.NewStateManager(cs) sm := stmgr.NewStateManager(cs)
var bms []stmgr.BlockMessages var bms []store.BlockMessages
for _, b := range blocks { for _, b := range blocks {
bm := stmgr.BlockMessages{ bm := store.BlockMessages{
Miner: b.Miner, Miner: b.Miner,
WinCount: 1, WinCount: 1,
} }