Merge branch 'master' into feat/sturdypost

This commit is contained in:
Andrew Jackson (Ajax) 2023-11-29 17:15:42 -06:00 committed by GitHub
commit e102e4f31f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 451 additions and 128 deletions

View File

@ -1016,29 +1016,28 @@ workflows:
requires: requires:
- build - build
suite: utest-unit-cli suite: utest-unit-cli
target: "./cli/... ./cmd/... ./api/..." executor: golang-2xl
get-params: true get-params: true
- test: - test:
name: test-unit-node name: test-unit-node
requires: requires:
- build - build
suite: utest-unit-node suite: utest-unit-node
target: "./node/..."
- test: - test:
name: test-unit-rest name: test-unit-rest
requires: requires:
- build - build
suite: utest-unit-rest suite: utest-unit-rest
target: "./blockstore/... ./build/... ./chain/... ./conformance/... ./gateway/... ./journal/... ./lib/... ./markets/... ./paychmgr/... ./tools/..."
executor: golang-2xl
- test: - test:
name: test-unit-storage name: test-unit-storage
requires: requires:
- build - build
suite: utest-unit-storage suite: utest-unit-storage
target: "./storage/... ./extern/..." target: "./storage/...
get-params: true
- test: - test:
go-test-flags: "-run=TestMulticoreSDR" go-test-flags: "-run=TestMulticoreSDR"
requires: requires:

View File

@ -567,6 +567,16 @@ workflows:
suite: utest-[[ $suite ]] suite: utest-[[ $suite ]]
target: "[[ $pkgs ]]" target: "[[ $pkgs ]]"
[[if eq $suite "unit-cli"]]get-params: true[[end]] [[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]] [[- end]]
- test: - test:
go-test-flags: "-run=TestMulticoreSDR" go-test-flags: "-run=TestMulticoreSDR"

View File

@ -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)) - 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: 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)) - 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 ## 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) - 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: - 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. - 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. - 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 # v 1.25.0 / 2023-11-22

View File

@ -824,7 +824,7 @@ type FullNode interface {
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) //perm:read EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) //perm:read
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, 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 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 EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) //perm:read

View File

@ -114,7 +114,7 @@ type Gateway interface {
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error)
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, 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) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error)

View File

@ -1042,7 +1042,7 @@ func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
} }
// EthEstimateGas mocks base method. // 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() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1) ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1)
ret0, _ := ret[0].(ethtypes.EthUint64) ret0, _ := ret[0].(ethtypes.EthUint64)

View File

@ -255,7 +255,7 @@ type FullNodeMethods struct {
EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` 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"` 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) `` 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) `` 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 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 { if s.Internal.EthEstimateGas == nil {
return *new(ethtypes.EthUint64), ErrNotSupported return *new(ethtypes.EthUint64), ErrNotSupported
} }
return s.Internal.EthEstimateGas(p0, p1) 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 return *new(ethtypes.EthUint64), ErrNotSupported
} }
@ -4400,14 +4400,14 @@ func (s *GatewayStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error)
return *new(ethtypes.EthUint64), ErrNotSupported 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 { if s.Internal.EthEstimateGas == nil {
return *new(ethtypes.EthUint64), ErrNotSupported return *new(ethtypes.EthUint64), ErrNotSupported
} }
return s.Internal.EthEstimateGas(p0, p1) 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 return *new(ethtypes.EthUint64), ErrNotSupported
} }

View File

@ -5,5 +5,8 @@ import (
) )
func IsNearUpgrade(epoch, upgradeEpoch abi.ChainEpoch) bool { func IsNearUpgrade(epoch, upgradeEpoch abi.ChainEpoch) bool {
if upgradeEpoch < 0 {
return false
}
return epoch > upgradeEpoch-Finality && epoch < upgradeEpoch+Finality return epoch > upgradeEpoch-Finality && epoch < upgradeEpoch+Finality
} }

Binary file not shown.

Binary file not shown.

View File

@ -42,7 +42,7 @@ func TestIndexSeeks(t *testing.T) {
cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), filcns.Weight, nil) cs := store.NewChainStore(nbs, nbs, syncds.MutexWrap(datastore.NewMapDatastore()), filcns.Weight, nil)
defer cs.Close() //nolint:errcheck defer cs.Close() //nolint:errcheck
_, err = cs.Import(ctx, bytes.NewReader(gencar)) _, _, err = cs.Import(ctx, bytes.NewReader(gencar))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -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. // TODO: writing only to the state blockstore is incorrect.
// At this time, both the state and chain blockstores are backed by the // At this time, both the state and chain blockstores are backed by the
// universal store. When we physically segregate the stores, we will need // 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) br, err := carv2.NewBlockReader(r)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loadcar failed: %w", err) return nil, nil, xerrors.Errorf("loadcar failed: %w", err)
} }
s := cs.StateBlockstore() s := cs.StateBlockstore()
@ -80,27 +80,51 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
putThrottle <- nil 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 var buf []blocks.Block
for { for {
blk, err := br.Next() blk, err := br.Next()
if err != nil { if err != nil {
// we're at the end
if err == io.EOF { if err == io.EOF {
if len(buf) > 0 { if len(buf) > 0 {
if err := s.PutMany(ctx, buf); err != nil { if err := s.PutMany(ctx, buf); err != nil {
return nil, err return nil, nil, err
} }
} }
break 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) buf = append(buf, blk)
if len(buf) > 1000 { if len(buf) > 1000 {
if lastErr := <-putThrottle; lastErr != nil { // consume one error to have the right to add one 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) { go func(buf []blocks.Block) {
@ -113,13 +137,17 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
// check errors // check errors
for i := 0; i < parallelPuts; i++ { for i := 0; i < parallelPuts; i++ {
if lastErr := <-putThrottle; lastErr != nil { 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...)) root, err := cs.LoadTipSet(ctx, types.NewTipSetKey(br.Roots...))
if err != nil { 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 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 { 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 type walkSchedTaskType int

View File

@ -118,7 +118,7 @@ func TestChainExportImport(t *testing.T) {
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil) cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
defer cs.Close() //nolint:errcheck defer cs.Close() //nolint:errcheck
root, err := cs.Import(context.TODO(), buf) root, _, err := cs.Import(context.TODO(), buf)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -153,7 +153,7 @@ func TestChainImportTipsetKeyCid(t *testing.T) {
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil) cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
defer cs.Close() //nolint:errcheck defer cs.Close() //nolint:errcheck
root, err := cs.Import(ctx, buf) root, _, err := cs.Import(ctx, buf)
require.NoError(t, err) require.NoError(t, err)
require.Truef(t, root.Equals(last), "imported chain differed from exported chain") 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) cs := store.NewChainStore(nbs, nbs, ds, filcns.Weight, nil)
defer cs.Close() //nolint:errcheck defer cs.Close() //nolint:errcheck
root, err := cs.Import(context.TODO(), buf) root, _, err := cs.Import(context.TODO(), buf)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -799,6 +799,45 @@ func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode []
return ethAddr, nil 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, &params)
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 // EthFeeHistoryParams handles raw jsonrpc params for eth_feeHistory
type EthFeeHistoryParams struct { type EthFeeHistoryParams struct {
BlkCount EthUint64 BlkCount EthUint64

View File

@ -304,7 +304,7 @@ var importBenchCmd = &cli.Command{
return fmt.Errorf("no CAR file provided for import") 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 { if err != nil {
return err return err
} }

View File

@ -658,6 +658,10 @@ var simpleWinningPost = &cli.Command{
Usage: "pass miner address (only necessary if using existing sectorbuilder)", Usage: "pass miner address (only necessary if using existing sectorbuilder)",
Value: "t01000", Value: "t01000",
}, },
&cli.BoolFlag{
Name: "show-inputs",
Usage: "output inputs for winning post generation",
},
}, },
ArgsUsage: "[sealed] [cache] [comm R] [sector num]", ArgsUsage: "[sealed] [cache] [comm R] [sector num]",
Action: func(cctx *cli.Context) error { 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("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.Printf("Proof %s (%s)\n", end.Sub(challenge), bps(sectorSize, 1, end.Sub(challenge)))
fmt.Println(base64.StdEncoding.EncodeToString(proof[0].ProofBytes)) 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 return nil
}, },
} }

View File

@ -62,7 +62,7 @@ var genesisVerifyCmd = &cli.Command{
return xerrors.Errorf("opening the car file: %w", err) 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 { if err != nil {
return err return err
} }

View File

@ -585,7 +585,7 @@ func ImportChain(ctx context.Context, r repo.Repo, fname string, snapshot bool)
} }
bar.Start() bar.Start()
ts, err := cst.Import(ctx, ir) ts, gen, err := cst.Import(ctx, ir)
bar.Finish() bar.Finish()
if err != nil { 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) return xerrors.Errorf("flushing validation cache failed: %w", err)
} }
gb, err := cst.GetTipsetByHeight(ctx, 0, ts, true) log.Infof("setting genesis")
if err != nil { err = cst.SetGenesis(ctx, gen)
return err
}
err = cst.SetGenesis(ctx, gb.Blocks()[0])
if err != nil { if err != nil {
return err return err
} }
if !snapshot { if !snapshot {
shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), gb.MinTimestamp(), nil) shd, err := drand.BeaconScheduleFromDrandSchedule(build.DrandConfigSchedule(), gen.Timestamp, nil)
if err != nil { if err != nil {
return xerrors.Errorf("failed to construct beacon schedule: %w", err) return xerrors.Errorf("failed to construct beacon schedule: %w", err)
} }

View File

@ -2402,14 +2402,7 @@ Perms: read
Inputs: Inputs:
```json ```json
[ [
{ "Bw=="
"from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031",
"gas": "0x5",
"gasPrice": "0x0",
"value": "0x0",
"data": "0x07"
}
] ]
``` ```

View File

@ -131,7 +131,7 @@ type TargetAPI interface {
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error)
EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error)
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, 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) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error)

View File

@ -353,13 +353,19 @@ func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt
return gw.target.EthMaxPriorityFeePerGas(ctx) 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 { if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
return 0, err return 0, err
} }
// todo limit gas? to what? // 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) { func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {

View File

@ -3,6 +3,7 @@ package itests
import ( import (
"context" "context"
"encoding/hex" "encoding/hex"
"encoding/json"
"os" "os"
"testing" "testing"
"time" "time"
@ -272,10 +273,13 @@ func TestEthAccountAbstractionFailsFromEvmActor(t *testing.T) {
contract, err := hex.DecodeString(string(contractHex)) contract, err := hex.DecodeString(string(contractHex))
require.NoError(t, err) require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
From: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)

View File

@ -35,7 +35,7 @@ type ethAPIRaw struct {
EthBlockNumber func(context.Context) (json.RawMessage, error) EthBlockNumber func(context.Context) (json.RawMessage, error)
EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error)
EthChainId func(context.Context) (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) EthFeeHistory func(context.Context, ethtypes.EthUint64, string, []float64) (json.RawMessage, error)
EthGasPrice func(context.Context) (json.RawMessage, error) EthGasPrice func(context.Context) (json.RawMessage, error)
EthGetBalance func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (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", method: "eth_estimateGas",
call: func(a *ethAPIRaw) (json.RawMessage, error) { 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, From: &senderEthAddr,
Data: contractBin, 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 { 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, From: &senderEthAddr,
Data: contractBin, Data: contractBin,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)

View File

@ -60,10 +60,13 @@ func TestDeployment(t *testing.T) {
// verify the deployer address is an Placeholder. // verify the deployer address is an Placeholder.
client.AssertActorType(ctx, deployer, manifest.PlaceholderKey) client.AssertActorType(ctx, deployer, manifest.PlaceholderKey)
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
From: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)

View File

@ -3,6 +3,7 @@ package itests
import ( import (
"context" "context"
"encoding/hex" "encoding/hex"
"encoding/json"
"os" "os"
"testing" "testing"
"time" "time"
@ -47,10 +48,13 @@ func TestTransactionHashLookup(t *testing.T) {
// send some funds to the f410 address // send some funds to the f410 address
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) 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: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
@ -350,10 +354,13 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) {
// send some funds to the f410 address // send some funds to the f410 address
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) 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: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)

View File

@ -3,17 +3,21 @@ package itests
import ( import (
"context" "context"
"encoding/hex" "encoding/hex"
"encoding/json"
"os" "os"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require" "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/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
builtin2 "github.com/filecoin-project/go-state-types/builtin" 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/go-state-types/manifest"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store" "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)) kit.SendFunds(ctx, t, client, deployer, types.FromFil(1000))
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ blkParam := ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{
Tx: ethtypes.EthCall{
From: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
},
BlkParam: &blkParam,
}) })
require.NoError(t, err) require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
require.NoError(t, err) require.NoError(t, err)
@ -231,11 +242,14 @@ func TestContractInvocation(t *testing.T) {
params, err := hex.DecodeString("f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064") params, err := hex.DecodeString("f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064")
require.NoError(t, err) require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
From: &ethAddr, From: &ethAddr,
To: &contractAddr, To: &contractAddr,
Data: params, Data: params,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) 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) { 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: &ethAddr, From: &ethAddr,
Data: contract, Data: contract,
}) }})
if err != nil {
return nil, err
}
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -378,7 +397,54 @@ func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr eth
}, nil }, 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 blockTime := 10 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
@ -394,49 +460,48 @@ func TestEthTxFromNativeAccount(t *testing.T) {
Method: builtin2.MethodsEVM.InvokeContract, 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) sMsg, err := client.MpoolPushMessage(ctx, msg, nil)
require.NoError(t, err) require.NoError(t, err)
client.WaitMsg(ctx, sMsg.Cid()) client.WaitMsg(ctx, sMsg.Cid())
hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid()) hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
require.NoError(t, err) require.NoError(t, err)
tx, err := client.EthGetTransactionByHash(ctx, hash) tx, err := client.EthGetTransactionByHash(ctx, hash)
require.NoError(t, err) 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. // Expect the decoded input.
require.EqualValues(t, input, tx.Input) require.EqualValues(t, input, tx.Input)
}
// Invoke the contract, but with incorrectly encoded input. We expect this to be abi-encoded // Invoke a contract, but with incorrectly encoded input. We expect this to be abi-encoded as if it
// as if it were any other method call. // 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 ens.InterconnectAll().BeginMining(blockTime)
require.NoError(t, err)
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) require.NoError(t, err)
client.WaitMsg(ctx, sMsg.Cid()) client.WaitMsg(ctx, sMsg.Cid())
hash, err = client.EthGetTransactionHashByCid(ctx, sMsg.Cid()) hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
require.NoError(t, err) require.NoError(t, err)
tx, err = client.EthGetTransactionByHash(ctx, hash) tx, err := client.EthGetTransactionByHash(ctx, hash)
require.NoError(t, err) require.NoError(t, err)
const expectedHex1 = "868e10c4" + // "handle filecoin method" function selector const expectedHex1 = "868e10c4" + // "handle filecoin method" function selector
@ -451,24 +516,39 @@ func TestEthTxFromNativeAccount(t *testing.T) {
// Input: 1, 2, 3, 4 // Input: 1, 2, 3, 4
"0102030400000000000000000000000000000000000000000000000000000000" "0102030400000000000000000000000000000000000000000000000000000000"
input, err = hex.DecodeString(expectedHex1) input, err := hex.DecodeString(expectedHex1)
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, input, tx.Input) 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) require.NoError(t, err)
client.WaitMsg(ctx, sMsg.Cid()) client.WaitMsg(ctx, sMsg.Cid())
hash, err = client.EthGetTransactionHashByCid(ctx, sMsg.Cid()) hash, err := client.EthGetTransactionHashByCid(ctx, sMsg.Cid())
require.NoError(t, err) require.NoError(t, err)
tx, err = client.EthGetTransactionByHash(ctx, hash) tx, err := client.EthGetTransactionByHash(ctx, hash)
require.NoError(t, err) require.NoError(t, err)
const expectedHex2 = "868e10c4" + // "handle filecoin method" function selector const expectedHex = "868e10c4" + // "handle filecoin method" function selector
// InvokeEVM+1 // InvokeEVM+1
"00000000000000000000000000000000000000000000000000000000e525aa16" + "00000000000000000000000000000000000000000000000000000000e525aa16" +
// CBOR multicodec (0x51) // CBOR multicodec (0x51)
@ -479,7 +559,51 @@ func TestEthTxFromNativeAccount(t *testing.T) {
"0000000000000000000000000000000000000000000000000000000000000004" + "0000000000000000000000000000000000000000000000000000000000000004" +
// Input: 1, 2, 3, 4 // Input: 1, 2, 3, 4
"0102030400000000000000000000000000000000000000000000000000000000" "0102030400000000000000000000000000000000000000000000000000000000"
input, err = hex.DecodeString(expectedHex2) input, err := hex.DecodeString(expectedHex)
require.NoError(t, err) require.NoError(t, err)
require.EqualValues(t, input, tx.Input) 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)
}

View File

@ -6,6 +6,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt" "fmt"
"testing" "testing"
"time" "time"
@ -657,11 +658,15 @@ func TestFEVMRecursiveActorCallEstimate(t *testing.T) {
t.Logf("running with %d recursive calls", r) t.Logf("running with %d recursive calls", r)
params := makeParams(r) params := makeParams(r)
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
From: &ethAddr, From: &ethAddr,
To: &contractAddr, To: &contractAddr,
Data: params, Data: params,
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
require.LessOrEqual(t, int64(gaslimit), build.BlockGasLimit) require.LessOrEqual(t, int64(gaslimit), build.BlockGasLimit)
@ -816,11 +821,14 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
contractEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr) contractEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr)
require.NoError(t, err) require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
From: &accntEth, From: &accntEth,
To: &contractEth, To: &contractEth,
Value: ethtypes.EthBigInt(big.NewInt(100)), Value: ethtypes.EthBigInt(big.NewInt(100)),
}) }})
require.NoError(t, err)
gaslimit, err := client.EthEstimateGas(ctx, gasParams)
require.NoError(t, err) require.NoError(t, err)
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
@ -1034,10 +1042,13 @@ func TestFEVMErrorParsing(t *testing.T) {
require.ErrorContains(t, err, expected) require.ErrorContains(t, err, expected)
}) })
t.Run("EthEstimateGas", func(t *testing.T) { t.Run("EthEstimateGas", func(t *testing.T) {
_, err := e.EthEstimateGas(ctx, ethtypes.EthCall{ gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{
To: &contractAddrEth, To: &contractAddrEth,
Data: entryPoint, Data: entryPoint,
}) }})
require.NoError(t, err)
_, err = e.EthEstimateGas(ctx, gasParams)
require.ErrorContains(t, err, expected) require.ErrorContains(t, err, expected)
}) })
}) })

View File

@ -223,3 +223,29 @@ func TestPledgeSynth(t *testing.T) {
runTest(t, 3) 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)
}
}

View File

@ -122,7 +122,7 @@ func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, e
return ethtypes.EthBigIntZero, ErrModuleDisabled 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 return 0, ErrModuleDisabled
} }

View File

@ -66,7 +66,7 @@ type EthModuleAPI interface {
NetListening(ctx context.Context) (bool, error) NetListening(ctx context.Context) (bool, error)
EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error)
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, 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) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error)
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, 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 return res, nil
} }
func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { func (a *EthModule) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) {
msg, err := ethCallToFilecoinMessage(ctx, tx) 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 { if err != nil {
return ethtypes.EthUint64(0), err return ethtypes.EthUint64(0), err
} }
@ -1017,7 +1022,16 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et
// gas estimation actually run. // gas estimation actually run.
msg.GasLimit = 0 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()) gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
if err != nil { if err != nil {
// On failure, GasEstimateMessageGas doesn't actually return the invocation result, // On failure, GasEstimateMessageGas doesn't actually return the invocation result,

View File

@ -29,6 +29,18 @@ import (
"github.com/filecoin-project/lotus/chain/vm" "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) { func getTipsetByBlockNumber(ctx context.Context, chain *store.ChainStore, blkParam string, strict bool) (*types.TipSet, error) {
if blkParam == "earliest" { if blkParam == "earliest" {
return nil, fmt.Errorf("block param \"earliest\" is not supported") 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) return ethtypes.EthTx{}, xerrors.Errorf("failed to calculate hash for ethTx: %w", err)
} }
} else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { // Secp Filecoin Message } 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()) tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
if err != nil { if err != nil {
return ethtypes.EthTx{}, err return ethtypes.EthTx{}, err
} }
} else { // BLS Filecoin message } 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()) tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
if err != nil { if err != nil {
return ethtypes.EthTx{}, err return ethtypes.EthTx{}, err
@ -482,19 +500,33 @@ func newEthTxFromSignedMessage(smsg *types.SignedMessage, st *state.StateTree) (
// Convert a native message to an eth transaction. // Convert a native message to an eth transaction.
// //
// - The state-tree must be from after the message was applied (ideally the following tipset). // - 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: // ethTxFromNativeMessage does NOT populate:
// - BlockHash // - BlockHash
// - BlockNumber // - BlockNumber
// - TransactionIndex // - TransactionIndex
// - Hash // - Hash
func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) ethtypes.EthTx { func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) (ethtypes.EthTx, error) {
// We don't care if we error here, conversion is best effort for non-eth transactions // Lookup the from address. This must succeed.
from, _ := lookupEthAddress(msg.From, st) from, err := lookupEthAddress(msg.From, st)
to, _ := lookupEthAddress(msg.To, 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 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 // For empty, we use "0" as the codec. Otherwise, we use CBOR for message
// parameters. // parameters.
@ -536,7 +568,7 @@ func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) ethtypes.Et
MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap), MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap),
MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium), MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium),
AccessList: []ethtypes.EthHash{}, AccessList: []ethtypes.EthHash{},
} }, nil
} }
func getSignedMessage(ctx context.Context, cs *store.ChainStore, msgCid cid.Cid) (*types.SignedMessage, error) { func getSignedMessage(ctx context.Context, cs *store.ChainStore, msgCid cid.Cid) (*types.SignedMessage, error) {

View File

@ -82,12 +82,12 @@ func ChainStore(lc fx.Lifecycle,
basebs dtypes.BaseBlockstore, basebs dtypes.BaseBlockstore,
weight store.WeightFunc, weight store.WeightFunc,
us stmgr.UpgradeSchedule, us stmgr.UpgradeSchedule,
j journal.Journal) *store.ChainStore { j journal.Journal) (*store.ChainStore, error) {
chain := store.NewChainStore(cbs, sbs, ds, weight, j) chain := store.NewChainStore(cbs, sbs, ds, weight, j)
if err := chain.Load(helpers.LifecycleCtx(mctx, lc)); err != nil { 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 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, func NetworkName(mctx helpers.MetricsCtx,

View File

@ -44,6 +44,10 @@ func (ss *SectorStats) updateSector(ctx context.Context, cfg sealiface.Config, i
ss.totals[toStatState(oldst, cfg.FinalizeEarly)]-- ss.totals[toStatState(oldst, cfg.FinalizeEarly)]--
ss.byState[oldst]-- ss.byState[oldst]--
if ss.byState[oldst] <= 0 {
delete(ss.byState, oldst)
}
mctx, _ := tag.New(ctx, tag.Upsert(metrics.SectorState, string(oldst))) mctx, _ := tag.New(ctx, tag.Upsert(metrics.SectorState, string(oldst)))
stats.Record(mctx, metrics.SectorStates.M(ss.byState[oldst])) stats.Record(mctx, metrics.SectorStates.M(ss.byState[oldst]))
} }