diff --git a/.circleci/config.yml b/.circleci/config.yml index 2230bfb00..2391a4e92 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -618,6 +618,11 @@ workflows: suite: itest-eth_account_abstraction target: "./itests/eth_account_abstraction_test.go" + - test: + name: test-itest-eth_api + suite: itest-eth_api + target: "./itests/eth_api_test.go" + - test: name: test-itest-eth_balance suite: itest-eth_balance diff --git a/api/api_full.go b/api/api_full.go index 3bd875dc7..c81bb2d6b 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -769,6 +769,8 @@ type FullNode interface { // // EthAccounts will always return [] since we don't expect Lotus to manage private keys EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read + // EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) //perm:read // EthBlockNumber returns the height of the latest (heaviest) TipSet EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read // EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 6e4873715..a5c65f07a 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -953,6 +953,21 @@ func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0) } +// EthAddressToFilecoinAddress mocks base method. +func (m *MockFullNode) EthAddressToFilecoinAddress(arg0 context.Context, arg1 ethtypes.EthAddress) (address.Address, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EthAddressToFilecoinAddress", arg0, arg1) + ret0, _ := ret[0].(address.Address) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// EthAddressToFilecoinAddress indicates an expected call of EthAddressToFilecoinAddress. +func (mr *MockFullNodeMockRecorder) EthAddressToFilecoinAddress(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAddressToFilecoinAddress", reflect.TypeOf((*MockFullNode)(nil).EthAddressToFilecoinAddress), arg0, arg1) +} + // EthBlockNumber mocks base method. func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) { m.ctrl.T.Helper() diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 2cfaa099a..f04bea2a9 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -244,6 +244,8 @@ type FullNodeMethods struct { EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `perm:"read"` + EthAddressToFilecoinAddress func(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) `perm:"read"` + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"` @@ -2007,6 +2009,17 @@ func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, e return *new([]ethtypes.EthAddress), ErrNotSupported } +func (s *FullNodeStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + if s.Internal.EthAddressToFilecoinAddress == nil { + return *new(address.Address), ErrNotSupported + } + return s.Internal.EthAddressToFilecoinAddress(p0, p1) +} + +func (s *FullNodeStub) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + return *new(address.Address), ErrNotSupported +} + func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { if s.Internal.EthBlockNumber == nil { return *new(ethtypes.EthUint64), ErrNotSupported diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index dabb581c2..06e43869d 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 86efad79f..24f5f7206 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index 545fe83cb..906c69d7a 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index e5db590da..1b44c69bd 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index f4b39e4be..a383f4946 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -68,6 +68,7 @@ * [CreateBackup](#CreateBackup) * [Eth](#Eth) * [EthAccounts](#EthAccounts) + * [EthAddressToFilecoinAddress](#EthAddressToFilecoinAddress) * [EthBlockNumber](#EthBlockNumber) * [EthCall](#EthCall) * [EthChainId](#EthChainId) @@ -2262,6 +2263,21 @@ Response: ] ``` +### EthAddressToFilecoinAddress +EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address + + +Perms: read + +Inputs: +```json +[ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" +] +``` + +Response: `"f01234"` + ### EthBlockNumber EthBlockNumber returns the height of the latest (heaviest) TipSet diff --git a/gateway/node.go b/gateway/node.go index 778f9e6f2..4f57d1d6a 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -88,6 +88,7 @@ type TargetAPI interface { StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error) WalletBalance(context.Context, address.Address) (types.BigInt, error) + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) diff --git a/itests/eth_api_test.go b/itests/eth_api_test.go new file mode 100644 index 000000000..39026637f --- /dev/null +++ b/itests/eth_api_test.go @@ -0,0 +1,47 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/builtin" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/itests/kit" +) + +func TestEthAddressToFilecoinAddress(t *testing.T) { + client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + secpKey, err := key.GenerateKey(types.KTDelegated) + require.NoError(t, err) + + filecoinKeyAddr, err := client.WalletImport(ctx, &secpKey.KeyInfo) + require.NoError(t, err) + + ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(filecoinKeyAddr) + require.NoError(t, err) + + apiFilAddr, err := client.EthAddressToFilecoinAddress(ctx, ethAddr) + require.NoError(t, err) + + require.Equal(t, filecoinKeyAddr, apiFilAddr) + + filecoinIdArr := builtin.StorageMarketActorAddr + ethAddr, err = ethtypes.EthAddressFromFilecoinAddress(filecoinIdArr) + require.NoError(t, err) + + apiFilAddr, err = client.EthAddressToFilecoinAddress(ctx, ethAddr) + require.NoError(t, err) + + require.Equal(t, filecoinIdArr, apiFilAddr) + +} diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 9abe00321..d86b02d4b 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -6,6 +6,7 @@ import ( "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/lotus/api" @@ -16,6 +17,10 @@ var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthR type EthModuleDummy struct{} +func (e *EthModuleDummy) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) { + return address.Undef, ErrModuleDisabled +} + func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) { return nil, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index d41a15c88..e30fe4da1 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -181,6 +181,10 @@ func (a *EthModule) EthAccounts(context.Context) ([]ethtypes.EthAddress, error) return []ethtypes.EthAddress{}, nil } +func (a *EthAPI) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) { + return ethAddress.ToFilecoinAddress() +} + func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) { blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts) if err != nil {