Skip to content

Commit d9505b0

Browse files
committed
Plumb StateCall's flushAllBlocks and write into result
1 parent e91b3b2 commit d9505b0

34 files changed

+300
-190
lines changed

api/api_full.go

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ type FullNode interface {
386386
// StateCall applies the message to the tipset's parent state. The
387387
// message is not applied on-top-of the messages in the passed-in
388388
// tipset.
389-
StateCall(ctx context.Context, p StateCallParams) (*InvocResult, error) //perm:read
389+
StateCall(ctx context.Context, p jsonrpc.RawParams) (*InvocResult, error) //perm:read
390390
// StateReplay replays a given message, assuming it was included in a block in the specified tipset.
391391
//
392392
// If a tipset key is provided, and a replacing message is not found on chain,
@@ -1271,12 +1271,7 @@ type InvocResult struct {
12711271
ExecutionTrace types.ExecutionTrace
12721272
Error string
12731273
Duration time.Duration
1274-
Blocks *InvocBlocks `json:",omitempty"`
1275-
}
1276-
1277-
type InvocBlocks struct {
1278-
Root cid.Cid
1279-
Blocks []Block
1274+
Blocks []Block `json:",omitempty"`
12801275
}
12811276

12821277
type Block struct {
@@ -1482,20 +1477,55 @@ type EthTxReceipt struct {
14821477
Type ethtypes.EthUint64 `json:"type"`
14831478
}
14841479

1480+
// StateCallParams is the parameters for the StateCall method.
14851481
type StateCallParams struct {
14861482
Message *types.Message `json:"message"`
14871483
TipSetKey types.TipSetKey `json:"tipsetKey"`
14881484
IncludeBlocks bool `json:"includeBlocks,omitempty"`
14891485
}
14901486

1491-
func (e *StateCallParams) ToArg() jsonrpc.RawParams {
1487+
// NewStateCallParams creates a new StateCallParams instance with the given message and tipset key.
1488+
func NewStateCallParams(msg *types.Message, tsk types.TipSetKey) StateCallParams {
1489+
return StateCallParams{
1490+
Message: msg,
1491+
TipSetKey: tsk,
1492+
IncludeBlocks: false,
1493+
}
1494+
}
1495+
1496+
// StateCallParamsFromRaw converts raw jsonrpc parameters to StateCallParams.
1497+
func StateCallParamsFromRaw(raw jsonrpc.RawParams) (StateCallParams, error) {
1498+
return jsonrpc.DecodeParams[StateCallParams](raw)
1499+
}
1500+
1501+
// ToRaw converts the StateCallParams to a jsonrpc.RawParams format for use with the StateCall
1502+
// method.
1503+
func (e StateCallParams) ToRaw() jsonrpc.RawParams {
1504+
if !e.IncludeBlocks {
1505+
// if we have 2 arguments, encode using the array format for backward compatibility with the
1506+
// old API, if a new client uses this to call an old server, it will be interpreted correctly
1507+
// as just 2 arguments
1508+
if b, err := json.Marshal([]any{e.Message, e.TipSetKey}); err == nil {
1509+
return jsonrpc.RawParams(b)
1510+
} // else fall through to the object format, maybe it'll work
1511+
}
1512+
// IncludeBlocks forces us to use the object format, so we can't be compatible with the old API
14921513
b, err := json.Marshal(e)
14931514
if err != nil {
14941515
return nil
14951516
}
14961517
return jsonrpc.RawParams(b)
14971518
}
14981519

1520+
// WithIncludeBlocks returns a new StateCallParams with IncludeBlocks set to true.
1521+
func (e StateCallParams) WithIncludeBlocks() StateCallParams {
1522+
return StateCallParams{
1523+
Message: e.Message,
1524+
TipSetKey: e.TipSetKey,
1525+
IncludeBlocks: true,
1526+
}
1527+
}
1528+
14991529
func (e *StateCallParams) UnmarshalJSON(b []byte) error {
15001530
if len(b) == 0 {
15011531
return xerrors.New("empty input")
@@ -1509,11 +1539,8 @@ func (e *StateCallParams) UnmarshalJSON(b []byte) error {
15091539
return err
15101540
}
15111541
*e = StateCallParams(alias)
1512-
return nil
1513-
}
1514-
1515-
// If input is an array, expect exactly two elements: Message and TipSetKey
1516-
if b[0] == '[' {
1542+
// If input is an array, expect exactly two elements: Message and TipSetKey
1543+
} else if b[0] == '[' {
15171544
var params []json.RawMessage
15181545
if err := json.Unmarshal(b, &params); err != nil {
15191546
return err
@@ -1527,10 +1554,15 @@ func (e *StateCallParams) UnmarshalJSON(b []byte) error {
15271554
if err := json.Unmarshal(params[1], &e.TipSetKey); err != nil {
15281555
return xerrors.Errorf("failed to unmarshal tipset key: %w", err)
15291556
}
1530-
return nil
1557+
} else {
1558+
return xerrors.Errorf("unexpected JSON input: expected object or array, got %q", string(b[0]))
1559+
}
1560+
1561+
if e.Message == nil {
1562+
return xerrors.New("message required")
15311563
}
15321564

1533-
return xerrors.Errorf("unexpected JSON input: expected object or array, got %q", string(b[0]))
1565+
return nil
15341566
}
15351567

15361568
func (e *StateCallParams) MarshalJSON() ([]byte, error) {

api/api_gateway.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ type Gateway interface {
6464
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
6565
MsigGetVestingSchedule(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MsigVesting, error)
6666
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
67-
StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*InvocResult, error)
67+
StateCall(ctx context.Context, p jsonrpc.RawParams) (*InvocResult, error)
6868
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (DealCollateralBounds, error)
6969
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error)
7070
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)

api/mocks/mock_full.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/proxy_gen.go

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v0api/full.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/filecoin-project/go-address"
1010
"github.com/filecoin-project/go-bitfield"
11+
"github.com/filecoin-project/go-jsonrpc"
1112
"github.com/filecoin-project/go-state-types/abi"
1213
"github.com/filecoin-project/go-state-types/builtin/v8/paych"
1314
verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
@@ -308,7 +309,7 @@ type FullNode interface {
308309
// StateCall applies the message to the tipset's parent state. The
309310
// message is not applied on-top-of the messages in the passed-in
310311
// tipset.
311-
StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) //perm:read
312+
StateCall(context.Context, jsonrpc.RawParams) (*api.InvocResult, error) //perm:read
312313
// StateReplay replays a given message, assuming it was included in a block in the specified tipset.
313314
//
314315
// If a tipset key is provided, and a replacing message is not found on chain,

api/v0api/gateway.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/ipfs/go-cid"
88

99
"github.com/filecoin-project/go-address"
10+
"github.com/filecoin-project/go-jsonrpc"
1011
"github.com/filecoin-project/go-state-types/abi"
1112
verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
1213
"github.com/filecoin-project/go-state-types/dline"
@@ -58,7 +59,7 @@ type Gateway interface {
5859
MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error)
5960
MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*api.MsigTransaction, error)
6061
StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error)
61-
StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error)
62+
StateCall(ctx context.Context, p jsonrpc.RawParams) (*api.InvocResult, error)
6263
StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error)
6364
StateDecodeParams(ctx context.Context, toAddr address.Address, method abi.MethodNum, params []byte, tsk types.TipSetKey) (interface{}, error)
6465
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)

api/v0api/proxy_gen.go

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v0api/v0mocks/mock_full.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
// Code generated by MockGen. DO NOT EDIT.
2-
// Source: github.com/filecoin-project/lotus/api/v0api (interfaces: FullNode)
3-
4-
// Package v0mocks is a generated GoMock package.
51
package v0mocks
62

73
import (
@@ -20,6 +16,7 @@ import (
2016

2117
address "github.com/filecoin-project/go-address"
2218
bitfield "github.com/filecoin-project/go-bitfield"
19+
"github.com/filecoin-project/go-jsonrpc"
2320
auth "github.com/filecoin-project/go-jsonrpc/auth"
2421
abi "github.com/filecoin-project/go-state-types/abi"
2522
big "github.com/filecoin-project/go-state-types/big"
@@ -1831,9 +1828,9 @@ func (mr *MockFullNodeMockRecorder) StateAllMinerFaults(arg0, arg1, arg2 interfa
18311828
}
18321829

18331830
// StateCall mocks base method.
1834-
func (m *MockFullNode) StateCall(arg0 context.Context, arg1 *types.Message, arg2 types.TipSetKey) (*api.InvocResult, error) {
1831+
func (m *MockFullNode) StateCall(arg0 context.Context, arg1 jsonrpc.RawParams) (*api.InvocResult, error) {
18351832
m.ctrl.T.Helper()
1836-
ret := m.ctrl.Call(m, "StateCall", arg0, arg1, arg2)
1833+
ret := m.ctrl.Call(m, "StateCall", arg0, arg1)
18371834
ret0, _ := ret[0].(*api.InvocResult)
18381835
ret1, _ := ret[1].(error)
18391836
return ret0, ret1

blockstore/accumulator.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package blockstore
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
block "github.com/ipfs/go-block-format"
8+
"github.com/ipfs/go-cid"
9+
)
10+
11+
// Accumulator is a type of blockstore that accumulates blocks in memory as they
12+
// are written. An Accumulator otherwise acts as a pass-through to the
13+
// underlying blockstore.
14+
//
15+
// Written blocks can be retrieved later using the GetBlocks method. This is
16+
// useful for testing and debugging purposes. Care should be taken when using
17+
// this feature for long-running applications where many blocks are written as
18+
// there is no automatic eviction mechanism. ClearBlocks can be used to
19+
// manually clear the accumulated blocks.
20+
type Accumulator struct {
21+
Blockstore
22+
23+
cids []cid.Cid
24+
lk sync.Mutex
25+
}
26+
27+
var (
28+
_ Blockstore = (*Accumulator)(nil)
29+
_ Viewer = (*Accumulator)(nil)
30+
)
31+
32+
// NewAccumulator creates a new Accumulator blockstore that wraps the given
33+
// Blockstore. The Accumulator will accumulate blocks in memory as they are
34+
// written. The blocks can be retrieved later using the GetBlocks method.
35+
func NewAccumulator(bs Blockstore) *Accumulator {
36+
return &Accumulator{
37+
Blockstore: bs,
38+
cids: make([]cid.Cid, 0),
39+
}
40+
}
41+
42+
func (acc *Accumulator) Put(ctx context.Context, b block.Block) error {
43+
acc.lk.Lock()
44+
acc.cids = append(acc.cids, b.Cid())
45+
acc.lk.Unlock()
46+
return acc.Blockstore.Put(ctx, b)
47+
}
48+
49+
func (acc *Accumulator) PutMany(ctx context.Context, blks []block.Block) error {
50+
acc.lk.Lock()
51+
for _, b := range blks {
52+
acc.cids = append(acc.cids, b.Cid())
53+
}
54+
acc.lk.Unlock()
55+
return acc.Blockstore.PutMany(ctx, blks)
56+
}
57+
58+
// GetBlocks returns the blocks that have been put into the accumulator.
59+
// It is safe to call this method concurrently with Put and PutMany.
60+
// The returned slice is the internal slice of blocks, and should be handled
61+
// with care if use of the blockstore is ongoing after this call.
62+
func (acc *Accumulator) GetBlocks(ctx context.Context) ([]block.Block, error) {
63+
acc.lk.Lock()
64+
defer acc.lk.Unlock()
65+
66+
blocks := make([]block.Block, len(acc.cids))
67+
for i, c := range acc.cids {
68+
b, err := acc.Blockstore.Get(ctx, c)
69+
if err != nil {
70+
return nil, err
71+
}
72+
blocks[i] = b
73+
}
74+
return blocks, nil
75+
}
76+
77+
// ClearBlocks clears the blocks that have been accumulated in the
78+
// Accumulator. This is useful for testing and debugging purposes.
79+
// It is safe to call this method concurrently with Put and PutMany.
80+
// The blocks are not removed from the underlying blockstore.
81+
func (acc *Accumulator) ClearBlocks() {
82+
acc.lk.Lock()
83+
defer acc.lk.Unlock()
84+
85+
acc.cids = acc.cids[:0]
86+
}

0 commit comments

Comments
 (0)