Merge branch 'master' into feat/sturdypost
This commit is contained in:
commit
e102e4f31f
@ -1016,29 +1016,28 @@ workflows:
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-cli
|
||||
target: "./cli/... ./cmd/... ./api/..."
|
||||
executor: golang-2xl
|
||||
get-params: true
|
||||
- test:
|
||||
name: test-unit-node
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-node
|
||||
target: "./node/..."
|
||||
|
||||
- test:
|
||||
name: test-unit-rest
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-rest
|
||||
target: "./blockstore/... ./build/... ./chain/... ./conformance/... ./gateway/... ./journal/... ./lib/... ./markets/... ./paychmgr/... ./tools/..."
|
||||
|
||||
executor: golang-2xl
|
||||
- test:
|
||||
name: test-unit-storage
|
||||
requires:
|
||||
- build
|
||||
suite: utest-unit-storage
|
||||
target: "./storage/... ./extern/..."
|
||||
|
||||
target: "./storage/...
|
||||
get-params: true
|
||||
- test:
|
||||
go-test-flags: "-run=TestMulticoreSDR"
|
||||
requires:
|
||||
|
@ -567,6 +567,16 @@ workflows:
|
||||
suite: utest-[[ $suite ]]
|
||||
target: "[[ $pkgs ]]"
|
||||
[[if eq $suite "unit-cli"]]get-params: true[[end]]
|
||||
[[- if eq $suite "unit-storage"]]
|
||||
get-params: true
|
||||
[[- end -]]
|
||||
[[- if eq $suite "unit-cli"]]
|
||||
executor: golang-2xl
|
||||
get-params: true
|
||||
[[- end -]]
|
||||
[[- if eq $suite "unit-rest"]]
|
||||
executor: golang-2xl
|
||||
[[- end -]]
|
||||
[[- end]]
|
||||
- test:
|
||||
go-test-flags: "-run=TestMulticoreSDR"
|
||||
|
@ -4,6 +4,8 @@
|
||||
- chore: Auto remove local chain data when importing chain file or snapshot ([filecoin-project/lotus#11277](https://github.com/filecoin-project/lotus/pull/11277))
|
||||
- feat: metric: export Mpool message count ([filecoin-project/lotus#11361](https://github.com/filecoin-project/lotus/pull/11361))
|
||||
- feat: sealing: load SectorsSummary from sealing SectorStats instead of calling API each time ([filecoin-project/lotus#11353](https://github.com/filecoin-project/lotus/pull/11353))
|
||||
- fix: miner info: Show correct sector state counts ([filecoin-project/lotus#11456](https://github.com/filecoin-project/lotus/pull/11456))
|
||||
- feat: add support for specifying block number when calling `eth_estimateGas` ([filecoin-project/lotus#11462](https://github.com/filecoin-project/lotus/pull/11462)).
|
||||
|
||||
## Improvements
|
||||
- fix: Add time slicing to splitstore purging step during compaction to reduce lock congestion [filecoin-project/lotus#11269](https://github.com/filecoin-project/lotus/pull/11269)
|
||||
@ -13,6 +15,7 @@
|
||||
- feat: Unambiguously translate native messages to Ethereum transactions by:
|
||||
- Detecting native messages that "look" like Ethereum transactions (creating smart contracts, invoking a smart contract, etc.), and decoding them as such.
|
||||
- Otherwise, ABI-encoding the inputs as if they were calls to a `handle_filecoin_method` Solidity method.
|
||||
- fix: ensure that the Ethereum API never returns "empty" addresses for native messages. When a "to" address cannot be resolved to a 0x-style address, it will be re-written to `0xff0000000000000000000000ffffffffffffffff`. This can only happen when the native transaction _reverted_ (failing to create an account at the specified "to" address).
|
||||
|
||||
# v 1.25.0 / 2023-11-22
|
||||
|
||||
|
@ -824,7 +824,7 @@ type FullNode interface {
|
||||
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) //perm:read
|
||||
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) //perm:read
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read
|
||||
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) //perm:read
|
||||
|
@ -114,7 +114,7 @@ type Gateway interface {
|
||||
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error)
|
||||
EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error)
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
|
||||
EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error)
|
||||
|
@ -1042,7 +1042,7 @@ func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
|
||||
}
|
||||
|
||||
// EthEstimateGas mocks base method.
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
|
@ -255,7 +255,7 @@ type FullNodeMethods struct {
|
||||
|
||||
EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
EthEstimateGas func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `perm:"read"`
|
||||
|
||||
@ -679,7 +679,7 @@ type GatewayMethods struct {
|
||||
|
||||
EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) ``
|
||||
|
||||
EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) ``
|
||||
EthEstimateGas func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) ``
|
||||
|
||||
EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) ``
|
||||
|
||||
@ -2134,14 +2134,14 @@ func (s *FullNodeStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthEstimateGas == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthEstimateGas(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
@ -4400,14 +4400,14 @@ func (s *GatewayStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error)
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthEstimateGas == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthEstimateGas(p0, p1)
|
||||
}
|
||||
|
||||
func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
|
@ -5,5 +5,8 @@ import (
|
||||
)
|
||||
|
||||
func IsNearUpgrade(epoch, upgradeEpoch abi.ChainEpoch) bool {
|
||||
if upgradeEpoch < 0 {
|
||||
return false
|
||||
}
|
||||
return epoch > upgradeEpoch-Finality && epoch < upgradeEpoch+Finality
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
@ -42,7 +42,7 @@ func TestIndexSeeks(t *testing.T) {
|
||||
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
_, err = cs.Import(ctx, bytes.NewReader(gencar))
|
||||
_, _, err = cs.Import(ctx, bytes.NewReader(gencar))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, error) {
|
||||
func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (head *types.TipSet, genesis *types.BlockHeader, err error) {
|
||||
// TODO: writing only to the state blockstore is incorrect.
|
||||
// At this time, both the state and chain blockstores are backed by the
|
||||
// universal store. When we physically segregate the stores, we will need
|
||||
@ -69,7 +69,7 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
||||
|
||||
br, err := carv2.NewBlockReader(r)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("loadcar failed: %w", err)
|
||||
return nil, nil, xerrors.Errorf("loadcar failed: %w", err)
|
||||
}
|
||||
|
||||
s := cs.StateBlockstore()
|
||||
@ -80,27 +80,51 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
||||
putThrottle <- nil
|
||||
}
|
||||
|
||||
if len(br.Roots) == 0 {
|
||||
return nil, nil, xerrors.Errorf("no roots in snapshot car file")
|
||||
}
|
||||
nextTailCid := br.Roots[0]
|
||||
|
||||
var tailBlock types.BlockHeader
|
||||
tailBlock.Height = abi.ChainEpoch(-1)
|
||||
|
||||
var buf []blocks.Block
|
||||
for {
|
||||
blk, err := br.Next()
|
||||
if err != nil {
|
||||
|
||||
// we're at the end
|
||||
if err == io.EOF {
|
||||
if len(buf) > 0 {
|
||||
if err := s.PutMany(ctx, buf); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// check for header block, looking for genesis
|
||||
if blk.Cid() == nextTailCid && tailBlock.Height != 0 {
|
||||
if err := tailBlock.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to unmarshal genesis block: %w", err)
|
||||
}
|
||||
if len(tailBlock.Parents) > 0 {
|
||||
nextTailCid = tailBlock.Parents[0]
|
||||
} else {
|
||||
// note: even the 0th block has a parent linking to the cbor genesis block
|
||||
return nil, nil, xerrors.Errorf("current block (epoch %d cid %s) has no parents", tailBlock.Height, tailBlock.Cid())
|
||||
}
|
||||
}
|
||||
|
||||
// append to batch
|
||||
buf = append(buf, blk)
|
||||
|
||||
if len(buf) > 1000 {
|
||||
if lastErr := <-putThrottle; lastErr != nil { // consume one error to have the right to add one
|
||||
return nil, lastErr
|
||||
return nil, nil, lastErr
|
||||
}
|
||||
|
||||
go func(buf []blocks.Block) {
|
||||
@ -113,13 +137,17 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
||||
// check errors
|
||||
for i := 0; i < parallelPuts; i++ {
|
||||
if lastErr := <-putThrottle; lastErr != nil {
|
||||
return nil, lastErr
|
||||
return nil, nil, lastErr
|
||||
}
|
||||
}
|
||||
|
||||
if tailBlock.Height != 0 {
|
||||
return nil, nil, xerrors.Errorf("expected genesis block to have height 0 (genesis), got %d: %s", tailBlock.Height, tailBlock.Cid())
|
||||
}
|
||||
|
||||
root, err := cs.LoadTipSet(ctx, types.NewTipSetKey(br.Roots...))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||
return nil, nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||
}
|
||||
|
||||
ts := root
|
||||
@ -135,10 +163,10 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
||||
}
|
||||
|
||||
if err := cs.PersistTipsets(ctx, tssToPersist); err != nil {
|
||||
return nil, xerrors.Errorf("failed to persist tipsets: %w", err)
|
||||
return nil, nil, xerrors.Errorf("failed to persist tipsets: %w", err)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
return root, &tailBlock, nil
|
||||
}
|
||||
|
||||
type walkSchedTaskType int
|
||||
|
@ -118,7 +118,7 @@ func TestChainExportImport(t *testing.T) {
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
root, err := cs.Import(context.TODO(), buf)
|
||||
root, _, err := cs.Import(context.TODO(), buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -153,7 +153,7 @@ func TestChainImportTipsetKeyCid(t *testing.T) {
|
||||
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
root, err := cs.Import(ctx, buf)
|
||||
root, _, err := cs.Import(ctx, buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Truef(t, root.Equals(last), "imported chain differed from exported chain")
|
||||
@ -202,7 +202,7 @@ func TestChainExportImportFull(t *testing.T) {
|
||||
cs := store.NewChainStore(nbs, nbs, ds, filcns.Weight, nil)
|
||||
defer cs.Close() //nolint:errcheck
|
||||
|
||||
root, err := cs.Import(context.TODO(), buf)
|
||||
root, _, err := cs.Import(context.TODO(), buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -799,6 +799,45 @@ func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode []
|
||||
return ethAddr, nil
|
||||
}
|
||||
|
||||
// EthEstimateGasParams handles raw jsonrpc params for eth_estimateGas
|
||||
type EthEstimateGasParams struct {
|
||||
Tx EthCall
|
||||
BlkParam *EthBlockNumberOrHash
|
||||
}
|
||||
|
||||
func (e *EthEstimateGasParams) UnmarshalJSON(b []byte) error {
|
||||
var params []json.RawMessage
|
||||
err := json.Unmarshal(b, ¶ms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch len(params) {
|
||||
case 2:
|
||||
err = json.Unmarshal(params[1], &e.BlkParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
err = json.Unmarshal(params[0], &e.Tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return xerrors.Errorf("expected 1 or 2 params, got %d", len(params))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e EthEstimateGasParams) MarshalJSON() ([]byte, error) {
|
||||
if e.BlkParam != nil {
|
||||
return json.Marshal([]interface{}{e.Tx, e.BlkParam})
|
||||
}
|
||||
return json.Marshal([]interface{}{e.Tx})
|
||||
}
|
||||
|
||||
// EthFeeHistoryParams handles raw jsonrpc params for eth_feeHistory
|
||||
type EthFeeHistoryParams struct {
|
||||
BlkCount EthUint64
|
||||
|
@ -304,7 +304,7 @@ var importBenchCmd = &cli.Command{
|
||||
return fmt.Errorf("no CAR file provided for import")
|
||||
}
|
||||
|
||||
head, err = cs.Import(cctx.Context, carFile)
|
||||
head, _, err = cs.Import(cctx.Context, carFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -658,6 +658,10 @@ var simpleWinningPost = &cli.Command{
|
||||
Usage: "pass miner address (only necessary if using existing sectorbuilder)",
|
||||
Value: "t01000",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "show-inputs",
|
||||
Usage: "output inputs for winning post generation",
|
||||
},
|
||||
},
|
||||
ArgsUsage: "[sealed] [cache] [comm R] [sector num]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
@ -728,6 +732,17 @@ var simpleWinningPost = &cli.Command{
|
||||
fmt.Printf("Vanilla %s (%s)\n", challenge.Sub(start), bps(sectorSize, 1, challenge.Sub(start)))
|
||||
fmt.Printf("Proof %s (%s)\n", end.Sub(challenge), bps(sectorSize, 1, end.Sub(challenge)))
|
||||
fmt.Println(base64.StdEncoding.EncodeToString(proof[0].ProofBytes))
|
||||
|
||||
if cctx.Bool("show-inputs") {
|
||||
fmt.Println("GenerateWinningPoStWithVanilla info:")
|
||||
|
||||
fmt.Printf(" wpt: %d\n", wpt)
|
||||
fmt.Printf(" mid: %d\n", mid)
|
||||
fmt.Printf(" rand: %x\n", rand)
|
||||
fmt.Printf(" vp: %x\n", vp)
|
||||
fmt.Printf(" proof: %x\n", proof)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ var genesisVerifyCmd = &cli.Command{
|
||||
return xerrors.Errorf("opening the car file: %w", err)
|
||||
}
|
||||
|
||||
ts, err := cs.Import(cctx.Context, f)
|
||||
ts, _, err := cs.Import(cctx.Context, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
||||
}
|
||||
|
||||
bar.Start()
|
||||
ts, err := cst.Import(ctx, ir)
|
||||
ts, gen, err := cst.Import(ctx, ir)
|
||||
bar.Finish()
|
||||
|
||||
if err != nil {
|
||||
@ -596,18 +596,14 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
|
||||
return xerrors.Errorf("flushing validation cache failed: %w", err)
|
||||
}
|
||||
|
||||
gb, err := cst.GetTipsetByHeight(ctx, 0, ts, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cst.SetGenesis(ctx, gb.Blocks()[0])
|
||||
log.Infof("setting genesis")
|
||||
err = cst.SetGenesis(ctx, gen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !snapshot {
|
||||
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), gb.MinTimestamp(), nil)
|
||||
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), gen.Timestamp, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to construct beacon schedule: %w", err)
|
||||
}
|
||||
|
@ -2402,14 +2402,7 @@ Perms: read
|
||||
Inputs:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
|
||||
"gas": "0x5",
|
||||
"gasPrice": "0x0",
|
||||
"value": "0x0",
|
||||
"data": "0x07"
|
||||
}
|
||||
"Bw=="
|
||||
]
|
||||
```
|
||||
|
||||
|
@ -131,7 +131,7 @@ type TargetAPI interface {
|
||||
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error)
|
||||
EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error)
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
|
||||
EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error)
|
||||
|
@ -353,13 +353,19 @@ func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt
|
||||
return gw.target.EthMaxPriorityFeePerGas(ctx)
|
||||
}
|
||||
|
||||
func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (gw *Node) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
// validate params
|
||||
_, err := jsonrpc.DecodeParams[ethtypes.EthEstimateGasParams](p)
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), xerrors.Errorf("decoding params: %w", err)
|
||||
}
|
||||
|
||||
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// todo limit gas? to what?
|
||||
return gw.target.EthEstimateGas(ctx, tx)
|
||||
return gw.target.EthEstimateGas(ctx, p)
|
||||
}
|
||||
|
||||
func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {
|
||||
|
@ -3,6 +3,7 @@ package itests
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@ -272,10 +273,13 @@ func TestEthAccountAbstractionFailsFromEvmActor(t *testing.T) {
|
||||
contract, err := hex.DecodeString(string(contractHex))
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
|
@ -35,7 +35,7 @@ type ethAPIRaw struct {
|
||||
EthBlockNumber func(context.Context) (json.RawMessage, error)
|
||||
EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error)
|
||||
EthChainId func(context.Context) (json.RawMessage, error)
|
||||
EthEstimateGas func(context.Context, ethtypes.EthCall) (json.RawMessage, error)
|
||||
EthEstimateGas func(context.Context, jsonrpc.RawParams) (json.RawMessage, error)
|
||||
EthFeeHistory func(context.Context, ethtypes.EthUint64, string, []float64) (json.RawMessage, error)
|
||||
EthGasPrice func(context.Context) (json.RawMessage, error)
|
||||
EthGetBalance func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error)
|
||||
@ -182,10 +182,13 @@ func TestEthOpenRPCConformance(t *testing.T) {
|
||||
{
|
||||
method: "eth_estimateGas",
|
||||
call: func(a *ethAPIRaw) (json.RawMessage, error) {
|
||||
return ethapi.EthEstimateGas(context.Background(), ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: &senderEthAddr,
|
||||
Data: contractBin,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
return ethapi.EthEstimateGas(ctx, gasParams)
|
||||
},
|
||||
},
|
||||
|
||||
@ -448,10 +451,13 @@ func TestEthOpenRPCConformance(t *testing.T) {
|
||||
}
|
||||
|
||||
func createRawSignedEthTx(ctx context.Context, t *testing.T, client *kit.TestFullNode, senderEthAddr ethtypes.EthAddress, receiverEthAddr ethtypes.EthAddress, senderKey *key.Key, contractBin []byte) []byte {
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: &senderEthAddr,
|
||||
Data: contractBin,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
|
@ -60,10 +60,13 @@ func TestDeployment(t *testing.T) {
|
||||
// verify the deployer address is an Placeholder.
|
||||
client.AssertActorType(ctx, deployer, manifest.PlaceholderKey)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
|
@ -3,6 +3,7 @@ package itests
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@ -47,10 +48,13 @@ func TestTransactionHashLookup(t *testing.T) {
|
||||
// send some funds to the f410 address
|
||||
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
@ -350,10 +354,13 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) {
|
||||
// send some funds to the f410 address
|
||||
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
|
@ -3,17 +3,21 @@ package itests
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtin2 "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
@ -44,12 +48,19 @@ func TestValueTransferValidSignature(t *testing.T) {
|
||||
|
||||
kit.SendFunds(ctx, t, client, deployer, types.FromFil(1000))
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
blkParam := ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{
|
||||
Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
},
|
||||
BlkParam: &blkParam,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -231,11 +242,14 @@ func TestContractInvocation(t *testing.T) {
|
||||
params, err := hex.DecodeString("f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064")
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
To: &contractAddr,
|
||||
Data: params,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
@ -350,10 +364,15 @@ func TestGetBlockByNumber(t *testing.T) {
|
||||
}
|
||||
|
||||
func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr ethtypes.EthAddress, contract []byte) (*ethtypes.EthTxArgs, error) {
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
Data: contract,
|
||||
})
|
||||
}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -378,7 +397,54 @@ func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr eth
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestEthTxFromNativeAccount(t *testing.T) {
|
||||
// Invoke a contract with empty input.
|
||||
func TestEthTxFromNativeAccount_EmptyInput(t *testing.T) {
|
||||
blockTime := 10 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
secpAddr, err := address.NewSecp256k1Address([]byte("foobar"))
|
||||
require.NoError(t, err)
|
||||
|
||||
msg := &types.Message{
|
||||
From: client.DefaultKey.Address,
|
||||
To: secpAddr,
|
||||
Value: abi.TokenAmount(types.MustParseFIL("100")),
|
||||
Method: builtin2.MethodsEVM.InvokeContract,
|
||||
}
|
||||
|
||||
sMsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(t, err)
|
||||
client.WaitMsg(ctx, sMsg.Cid())
|
||||
|
||||
hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
require.NoError(t, err)
|
||||
tx, err := client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect empty input params given that we "invoked" the contract (well, invoked ourselves).
|
||||
require.Equal(t, ethtypes.EthBytes{}, tx.Input)
|
||||
|
||||
// Validate the to/from addresses.
|
||||
toId, err := client.StateLookupID(ctx, msg.To, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
fromId, err := client.StateLookupID(ctx, msg.From, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedTo, err := ethtypes.EthAddressFromFilecoinAddress(toId)
|
||||
require.NoError(t, err)
|
||||
expectedFrom, err := ethtypes.EthAddressFromFilecoinAddress(fromId)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &expectedTo, tx.To)
|
||||
require.Equal(t, expectedFrom, tx.From)
|
||||
}
|
||||
|
||||
// Invoke a contract with non-empty input.
|
||||
func TestEthTxFromNativeAccount_NonEmptyInput(t *testing.T) {
|
||||
blockTime := 10 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||
|
||||
@ -394,49 +460,48 @@ func TestEthTxFromNativeAccount(t *testing.T) {
|
||||
Method: builtin2.MethodsEVM.InvokeContract,
|
||||
}
|
||||
|
||||
// Send a message with no input.
|
||||
var err error
|
||||
input := abi.CborBytes([]byte{0x1, 0x2, 0x3, 0x4})
|
||||
msg.Params, err = actors.SerializeParams(&input)
|
||||
require.NoError(t, err)
|
||||
|
||||
sMsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(t, err)
|
||||
client.WaitMsg(ctx, sMsg.Cid())
|
||||
|
||||
hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
require.NoError(t, err)
|
||||
tx, err := client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect empty input params given that we "invoked" the contract (well, invoked ourselves).
|
||||
require.Equal(t, ethtypes.EthBytes{}, tx.Input)
|
||||
|
||||
// Send a message with some input.
|
||||
|
||||
input := abi.CborBytes([]byte{0x1, 0x2, 0x3, 0x4})
|
||||
msg.Params, err = actors.SerializeParams(&input)
|
||||
require.NoError(t, err)
|
||||
|
||||
sMsg, err = client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(t, err)
|
||||
client.WaitMsg(ctx, sMsg.Cid())
|
||||
hash, err = client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
require.NoError(t, err)
|
||||
tx, err = client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect the decoded input.
|
||||
require.EqualValues(t, input, tx.Input)
|
||||
}
|
||||
|
||||
// Invoke the contract, but with incorrectly encoded input. We expect this to be abi-encoded
|
||||
// as if it were any other method call.
|
||||
// Invoke a contract, but with incorrectly encoded input. We expect this to be abi-encoded as if it
|
||||
// were any other method call.
|
||||
func TestEthTxFromNativeAccount_BadInput(t *testing.T) {
|
||||
blockTime := 10 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||
|
||||
msg.Params = input
|
||||
require.NoError(t, err)
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
sMsg, err = client.MpoolPushMessage(ctx, msg, nil)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
msg := &types.Message{
|
||||
From: client.DefaultKey.Address,
|
||||
To: client.DefaultKey.Address,
|
||||
Value: abi.TokenAmount(types.MustParseFIL("100")),
|
||||
Method: builtin2.MethodsEVM.InvokeContract,
|
||||
Params: []byte{0x1, 0x2, 0x3, 0x4},
|
||||
}
|
||||
|
||||
sMsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(t, err)
|
||||
client.WaitMsg(ctx, sMsg.Cid())
|
||||
hash, err = client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
require.NoError(t, err)
|
||||
tx, err = client.EthGetTransactionByHash(ctx, hash)
|
||||
tx, err := client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
const expectedHex1 = "868e10c4" + // "handle filecoin method" function selector
|
||||
@ -451,24 +516,39 @@ func TestEthTxFromNativeAccount(t *testing.T) {
|
||||
// Input: 1, 2, 3, 4
|
||||
"0102030400000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
input, err = hex.DecodeString(expectedHex1)
|
||||
input, err := hex.DecodeString(expectedHex1)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, input, tx.Input)
|
||||
|
||||
// Invoke a random method with the same input. We expect the same result as above, but with
|
||||
// a different method number.
|
||||
}
|
||||
|
||||
msg.Method++
|
||||
// Invoke a native method.
|
||||
func TestEthTxFromNativeAccount_NativeMethod(t *testing.T) {
|
||||
blockTime := 10 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||
|
||||
sMsg, err = client.MpoolPushMessage(ctx, msg, nil)
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
msg := &types.Message{
|
||||
From: client.DefaultKey.Address,
|
||||
To: client.DefaultKey.Address,
|
||||
Value: abi.TokenAmount(types.MustParseFIL("100")),
|
||||
Method: builtin2.MethodsEVM.InvokeContract + 1,
|
||||
Params: []byte{0x1, 0x2, 0x3, 0x4},
|
||||
}
|
||||
|
||||
sMsg, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||
require.NoError(t, err)
|
||||
client.WaitMsg(ctx, sMsg.Cid())
|
||||
hash, err = client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
|
||||
require.NoError(t, err)
|
||||
tx, err = client.EthGetTransactionByHash(ctx, hash)
|
||||
tx, err := client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
const expectedHex2 = "868e10c4" + // "handle filecoin method" function selector
|
||||
const expectedHex = "868e10c4" + // "handle filecoin method" function selector
|
||||
// InvokeEVM+1
|
||||
"00000000000000000000000000000000000000000000000000000000e525aa16" +
|
||||
// CBOR multicodec (0x51)
|
||||
@ -479,7 +559,51 @@ func TestEthTxFromNativeAccount(t *testing.T) {
|
||||
"0000000000000000000000000000000000000000000000000000000000000004" +
|
||||
// Input: 1, 2, 3, 4
|
||||
"0102030400000000000000000000000000000000000000000000000000000000"
|
||||
input, err = hex.DecodeString(expectedHex2)
|
||||
input, err := hex.DecodeString(expectedHex)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, input, tx.Input)
|
||||
}
|
||||
|
||||
// Send to an invalid receiver. We're checking to make sure we correctly set `txn.To` to the special
|
||||
// "reverted" eth addr.
|
||||
func TestEthTxFromNativeAccount_InvalidReceiver(t *testing.T) {
|
||||
blockTime := 10 * time.Millisecond
|
||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
to, err := address.NewActorAddress([]byte("foobar"))
|
||||
require.NoError(t, err)
|
||||
|
||||
msg := &types.Message{
|
||||
From: client.DefaultKey.Address,
|
||||
To: to,
|
||||
Value: abi.TokenAmount(types.MustParseFIL("100")),
|
||||
Method: builtin2.MethodsEVM.InvokeContract + 1,
|
||||
Params: []byte{0x1, 0x2, 0x3, 0x4},
|
||||
// We can't estimate gas for a failed message, so we hard-code these values.
|
||||
GasLimit: 10_000_000,
|
||||
GasFeeCap: abi.NewTokenAmount(10000),
|
||||
}
|
||||
|
||||
// We expect the "to" address to be the special "reverted" eth address.
|
||||
expectedTo, err := ethtypes.ParseEthAddress("ff0000000000000000000000ffffffffffffffff")
|
||||
require.NoError(t, err)
|
||||
|
||||
sMsg, err := client.WalletSignMessage(ctx, client.DefaultKey.Address, msg)
|
||||
require.NoError(t, err)
|
||||
k, err := client.MpoolPush(ctx, sMsg)
|
||||
require.NoError(t, err)
|
||||
res, err := client.StateWaitMsg(ctx, k, 3, api.LookbackNoLimit, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res.Receipt.ExitCode, exitcode.SysErrInvalidReceiver)
|
||||
|
||||
hash, err := client.EthGetTransactionHashByCid(ctx, k)
|
||||
require.NoError(t, err)
|
||||
tx, err := client.EthGetTransactionByHash(ctx, hash)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, &expectedTo, tx.To)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@ -657,11 +658,15 @@ func TestFEVMRecursiveActorCallEstimate(t *testing.T) {
|
||||
t.Logf("running with %d recursive calls", r)
|
||||
|
||||
params := makeParams(r)
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: ðAddr,
|
||||
To: &contractAddr,
|
||||
Data: params,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
require.LessOrEqual(t, int64(gaslimit), build.BlockGasLimit)
|
||||
|
||||
@ -816,11 +821,14 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
|
||||
contractEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
From: &accntEth,
|
||||
To: &contractEth,
|
||||
Value: ethtypes.EthBigInt(big.NewInt(100)),
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
|
||||
require.NoError(t, err)
|
||||
|
||||
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||
@ -1034,10 +1042,13 @@ func TestFEVMErrorParsing(t *testing.T) {
|
||||
require.ErrorContains(t, err, expected)
|
||||
})
|
||||
t.Run("EthEstimateGas", func(t *testing.T) {
|
||||
_, err := e.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
|
||||
To: &contractAddrEth,
|
||||
Data: entryPoint,
|
||||
})
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = e.EthEstimateGas(ctx, gasParams)
|
||||
require.ErrorContains(t, err, expected)
|
||||
})
|
||||
})
|
||||
|
@ -223,3 +223,29 @@ func TestPledgeSynth(t *testing.T) {
|
||||
runTest(t, 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSectorsSummary(t *testing.T) {
|
||||
kit.QuietMiningLogs()
|
||||
|
||||
blockTime := 50 * time.Millisecond
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
nPreseal := 2
|
||||
|
||||
_, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.PresealSectors(nPreseal))
|
||||
ens.InterconnectAll().BeginMining(blockTime)
|
||||
|
||||
miner.PledgeSectors(ctx, 1, 0, nil)
|
||||
|
||||
ms, err := miner.SectorsSummary(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, ms, 1) // all proving
|
||||
|
||||
for st, n := range ms {
|
||||
require.Equal(t, api.SectorState(sealing.Proving), st)
|
||||
require.Equal(t, 1+nPreseal, n)
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, e
|
||||
return ethtypes.EthBigIntZero, ErrModuleDisabled
|
||||
}
|
||||
|
||||
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
return 0, ErrModuleDisabled
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ type EthModuleAPI interface {
|
||||
NetListening(ctx context.Context) (bool, error)
|
||||
EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error)
|
||||
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error)
|
||||
EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error)
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
|
||||
@ -1007,8 +1007,13 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk ty
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
msg, err := ethCallToFilecoinMessage(ctx, tx)
|
||||
func (a *EthModule) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) {
|
||||
params, err := jsonrpc.DecodeParams[ethtypes.EthEstimateGasParams](p)
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), xerrors.Errorf("decoding params: %w", err)
|
||||
}
|
||||
|
||||
msg, err := ethCallToFilecoinMessage(ctx, params.Tx)
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), err
|
||||
}
|
||||
@ -1017,7 +1022,16 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et
|
||||
// gas estimation actually run.
|
||||
msg.GasLimit = 0
|
||||
|
||||
ts := a.Chain.GetHeaviestTipSet()
|
||||
var ts *types.TipSet
|
||||
if params.BlkParam == nil {
|
||||
ts = a.Chain.GetHeaviestTipSet()
|
||||
} else {
|
||||
ts, err = getTipsetByEthBlockNumberOrHash(ctx, a.Chain, *params.BlkParam)
|
||||
if err != nil {
|
||||
return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %v; %w", params.BlkParam, err)
|
||||
}
|
||||
}
|
||||
|
||||
gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
|
||||
if err != nil {
|
||||
// On failure, GasEstimateMessageGas doesn't actually return the invocation result,
|
||||
|
@ -29,6 +29,18 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
// The address used in messages to actors that have since been deleted.
|
||||
//
|
||||
// 0xff0000000000000000000000ffffffffffffffff
|
||||
var revertedEthAddress ethtypes.EthAddress
|
||||
|
||||
func init() {
|
||||
revertedEthAddress[0] = 0xff
|
||||
for i := 20 - 8; i < 20; i++ {
|
||||
revertedEthAddress[i] = 0xff
|
||||
}
|
||||
}
|
||||
|
||||
func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkParam string, strict bool) (*types.TipSet, error) {
|
||||
if blkParam == "earliest" {
|
||||
return nil, fmt.Errorf("block param \"earliest\" is not supported")
|
||||
@ -463,13 +475,19 @@ func newEthTxFromSignedMessage(smsg *types.SignedMessage, st *state.StateTree) (
|
||||
return ethtypes.EthTx{}, xerrors.Errorf("failed to calculate hash for ethTx: %w", err)
|
||||
}
|
||||
} else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { // Secp Filecoin Message
|
||||
tx = ethTxFromNativeMessage(smsg.VMMessage(), st)
|
||||
tx, err = ethTxFromNativeMessage(smsg.VMMessage(), st)
|
||||
if err != nil {
|
||||
return ethtypes.EthTx{}, err
|
||||
}
|
||||
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
|
||||
if err != nil {
|
||||
return ethtypes.EthTx{}, err
|
||||
}
|
||||
} else { // BLS Filecoin message
|
||||
tx = ethTxFromNativeMessage(smsg.VMMessage(), st)
|
||||
tx, err = ethTxFromNativeMessage(smsg.VMMessage(), st)
|
||||
if err != nil {
|
||||
return ethtypes.EthTx{}, err
|
||||
}
|
||||
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
|
||||
if err != nil {
|
||||
return ethtypes.EthTx{}, err
|
||||
@ -482,19 +500,33 @@ func newEthTxFromSignedMessage(smsg *types.SignedMessage, st *state.StateTree) (
|
||||
// Convert a native message to an eth transaction.
|
||||
//
|
||||
// - The state-tree must be from after the message was applied (ideally the following tipset).
|
||||
// - In some cases, the "to" address may be `0xff0000000000000000000000ffffffffffffffff`. This
|
||||
// means that the "to" address has not been assigned in the passed state-tree and can only
|
||||
// happen if the transaction reverted.
|
||||
//
|
||||
// ethTxFromNativeMessage does NOT populate:
|
||||
// - BlockHash
|
||||
// - BlockNumber
|
||||
// - TransactionIndex
|
||||
// - Hash
|
||||
func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) ethtypes.EthTx {
|
||||
// We don't care if we error here, conversion is best effort for non-eth transactions
|
||||
from, _ := lookupEthAddress(msg.From, st)
|
||||
to, _ := lookupEthAddress(msg.To, st)
|
||||
func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) (ethtypes.EthTx, error) {
|
||||
// Lookup the from address. This must succeed.
|
||||
from, err := lookupEthAddress(msg.From, st)
|
||||
if err != nil {
|
||||
return ethtypes.EthTx{}, xerrors.Errorf("failed to lookup sender address %s when converting a native message to an eth txn: %w", msg.From, err)
|
||||
}
|
||||
// Lookup the to address. If the recipient doesn't exist, we replace the address with a
|
||||
// known sentinel address.
|
||||
to, err := lookupEthAddress(msg.To, st)
|
||||
if err != nil {
|
||||
if !errors.Is(err, types.ErrActorNotFound) {
|
||||
return ethtypes.EthTx{}, xerrors.Errorf("failed to lookup receiver address %s when converting a native message to an eth txn: %w", msg.To, err)
|
||||
}
|
||||
to = revertedEthAddress
|
||||
}
|
||||
toPtr := &to
|
||||
|
||||
// Convert the input parameters to "solidity ABI".
|
||||
// Finally, convert the input parameters to "solidity ABI".
|
||||
|
||||
// For empty, we use "0" as the codec. Otherwise, we use CBOR for message
|
||||
// parameters.
|
||||
@ -536,7 +568,7 @@ func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) ethtypes.Et
|
||||
MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap),
|
||||
MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium),
|
||||
AccessList: []ethtypes.EthHash{},
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getSignedMessage(ctx context.Context, cs *store.ChainStore, msgCid cid.Cid) (*types.SignedMessage, error) {
|
||||
|
@ -82,12 +82,12 @@ func ChainStore(lc fx.Lifecycle,
|
||||
basebs dtypes.BaseBlockstore,
|
||||
weight store.WeightFunc,
|
||||
us stmgr.UpgradeSchedule,
|
||||
j journal.Journal) *store.ChainStore {
|
||||
j journal.Journal) (*store.ChainStore, error) {
|
||||
|
||||
chain := store.NewChainStore(cbs, sbs, ds, weight, j)
|
||||
|
||||
if err := chain.Load(helpers.LifecycleCtx(mctx, lc)); err != nil {
|
||||
log.Warnf("loading chain state from disk: %s", err)
|
||||
return nil, xerrors.Errorf("loading chain state from disk: %w", err)
|
||||
}
|
||||
|
||||
var startHook func(context.Context) error
|
||||
@ -108,7 +108,7 @@ func ChainStore(lc fx.Lifecycle,
|
||||
},
|
||||
})
|
||||
|
||||
return chain
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
func NetworkName(mctx helpers.MetricsCtx,
|
||||
|
@ -44,6 +44,10 @@ func (ss *SectorStats) updateSector(ctx context.Context, cfg sealiface.Config, i
|
||||
ss.totals[toStatState(oldst, cfg.FinalizeEarly)]--
|
||||
ss.byState[oldst]--
|
||||
|
||||
if ss.byState[oldst] <= 0 {
|
||||
delete(ss.byState, oldst)
|
||||
}
|
||||
|
||||
mctx, _ := tag.New(ctx, tag.Upsert(metrics.SectorState, string(oldst)))
|
||||
stats.Record(mctx, metrics.SectorStates.M(ss.byState[oldst]))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user