Merge pull request #8486 from filecoin-project/gstuart/robust-address-endpoint

Feat: API: Implement StateLookupRobustAddress
This commit is contained in:
Geoff Stuart 2022-04-19 11:37:23 -04:00 committed by GitHub
commit a3a3fefb1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 147 additions and 2 deletions

View File

@ -874,6 +874,11 @@ workflows:
suite: itest-get_messages_in_ts suite: itest-get_messages_in_ts
target: "./itests/get_messages_in_ts_test.go" target: "./itests/get_messages_in_ts_test.go"
- test:
name: test-itest-lookup_robust_address
suite: itest-lookup_robust_address
target: "./itests/lookup_robust_address_test.go"
- test: - test:
name: test-itest-mempool name: test-itest-mempool
suite: itest-mempool suite: itest-mempool

View File

@ -522,8 +522,10 @@ type FullNode interface {
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*MarketDeal, error) //perm:read StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*MarketDeal, error) //perm:read
// StateLookupID retrieves the ID address of the given address // StateLookupID retrieves the ID address of the given address
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) //perm:read StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) //perm:read
// StateAccountKey returns the public key address of the given ID address // StateAccountKey returns the public key address of the given ID address for secp and bls accounts
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) //perm:read StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) //perm:read
// StateLookupRobustAddress returns the public key address of the given ID address for non-account addresses (multisig, miners etc)
StateLookupRobustAddress(context.Context, address.Address, types.TipSetKey) (address.Address, error) //perm:read
// StateChangedActors returns all the actors whose states change between the two given state CIDs // StateChangedActors returns all the actors whose states change between the two given state CIDs
// TODO: Should this take tipset keys instead? // TODO: Should this take tipset keys instead?
StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) //perm:read StateChangedActors(context.Context, cid.Cid, cid.Cid) (map[string]types.Actor, error) //perm:read

View File

@ -2496,6 +2496,21 @@ func (mr *MockFullNodeMockRecorder) StateLookupID(arg0, arg1, arg2 interface{})
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateLookupID", reflect.TypeOf((*MockFullNode)(nil).StateLookupID), arg0, arg1, arg2) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateLookupID", reflect.TypeOf((*MockFullNode)(nil).StateLookupID), arg0, arg1, arg2)
} }
// StateLookupRobustAddress mocks base method.
func (m *MockFullNode) StateLookupRobustAddress(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (address.Address, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "StateLookupRobustAddress", arg0, arg1, arg2)
ret0, _ := ret[0].(address.Address)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// StateLookupRobustAddress indicates an expected call of StateLookupRobustAddress.
func (mr *MockFullNodeMockRecorder) StateLookupRobustAddress(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateLookupRobustAddress", reflect.TypeOf((*MockFullNode)(nil).StateLookupRobustAddress), arg0, arg1, arg2)
}
// StateMarketBalance mocks base method. // StateMarketBalance mocks base method.
func (m *MockFullNode) StateMarketBalance(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (api.MarketBalance, error) { func (m *MockFullNode) StateMarketBalance(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (api.MarketBalance, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -364,6 +364,8 @@ type FullNodeStruct struct {
StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` StateLookupID func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"`
StateLookupRobustAddress func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"`
StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `perm:"read"` StateMarketBalance func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) `perm:"read"`
StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]MarketDeal, error) `perm:"read"` StateMarketDeals func(p0 context.Context, p1 types.TipSetKey) (map[string]MarketDeal, error) `perm:"read"`
@ -2528,6 +2530,17 @@ func (s *FullNodeStub) StateLookupID(p0 context.Context, p1 address.Address, p2
return *new(address.Address), ErrNotSupported return *new(address.Address), ErrNotSupported
} }
func (s *FullNodeStruct) StateLookupRobustAddress(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {
if s.Internal.StateLookupRobustAddress == nil {
return *new(address.Address), ErrNotSupported
}
return s.Internal.StateLookupRobustAddress(p0, p1, p2)
}
func (s *FullNodeStub) StateLookupRobustAddress(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {
return *new(address.Address), ErrNotSupported
}
func (s *FullNodeStruct) StateMarketBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) { func (s *FullNodeStruct) StateMarketBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) {
if s.Internal.StateMarketBalance == nil { if s.Internal.StateMarketBalance == nil {
return *new(MarketBalance), ErrNotSupported return *new(MarketBalance), ErrNotSupported

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"sync" "sync"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/specs-actors/v7/actors/migration/nv15" "github.com/filecoin-project/specs-actors/v7/actors/migration/nv15"
"github.com/filecoin-project/lotus/chain/rand" "github.com/filecoin-project/lotus/chain/rand"
@ -22,6 +24,7 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
_init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
@ -318,6 +321,48 @@ func (sm *StateManager) LookupID(ctx context.Context, addr address.Address, ts *
return state.LookupID(addr) return state.LookupID(addr)
} }
func (sm *StateManager) LookupRobustAddress(ctx context.Context, idAddr address.Address, ts *types.TipSet) (address.Address, error) {
idAddrDecoded, err := address.IDFromAddress(idAddr)
if err != nil {
return address.Undef, xerrors.Errorf("failed to decode provided address as id addr: %w", err)
}
cst := cbor.NewCborStore(sm.cs.StateBlockstore())
wrapStore := adt.WrapStore(ctx, cst)
stateTree, err := state.LoadStateTree(cst, sm.parentState(ts))
if err != nil {
return address.Undef, xerrors.Errorf("load state tree: %w", err)
}
initActor, err := stateTree.GetActor(_init.Address)
if err != nil {
return address.Undef, xerrors.Errorf("load init actor: %w", err)
}
initState, err := _init.Load(wrapStore, initActor)
if err != nil {
return address.Undef, xerrors.Errorf("load init state: %w", err)
}
robustAddr := address.Undef
err = initState.ForEachActor(func(id abi.ActorID, addr address.Address) error {
if uint64(id) == idAddrDecoded {
robustAddr = addr
// Hacky way to early return from ForEach
return xerrors.New("robust address found")
}
return nil
})
if robustAddr == address.Undef {
if err == nil {
return address.Undef, xerrors.Errorf("Address %s not found", idAddr.String())
}
return address.Undef, xerrors.Errorf("finding address: %w", err)
}
return robustAddr, nil
}
func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) error { func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) error {
tschain := []*types.TipSet{ts} tschain := []*types.TipSet{ts}
for ts.Height() != 0 { for ts.Height() != 0 {

View File

@ -181,6 +181,7 @@
* [StateListMessages](#StateListMessages) * [StateListMessages](#StateListMessages)
* [StateListMiners](#StateListMiners) * [StateListMiners](#StateListMiners)
* [StateLookupID](#StateLookupID) * [StateLookupID](#StateLookupID)
* [StateLookupRobustAddress](#StateLookupRobustAddress)
* [StateMarketBalance](#StateMarketBalance) * [StateMarketBalance](#StateMarketBalance)
* [StateMarketDeals](#StateMarketDeals) * [StateMarketDeals](#StateMarketDeals)
* [StateMarketParticipants](#StateMarketParticipants) * [StateMarketParticipants](#StateMarketParticipants)
@ -5037,7 +5038,7 @@ A nil TipSetKey can be provided as a param, this will cause the heaviest tipset
### StateAccountKey ### StateAccountKey
StateAccountKey returns the public key address of the given ID address StateAccountKey returns the public key address of the given ID address for secp and bls accounts
Perms: read Perms: read
@ -5783,6 +5784,29 @@ Response:
StateLookupID retrieves the ID address of the given address StateLookupID retrieves the ID address of the given address
Perms: read
Inputs:
```json
[
"f01234",
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
{
"/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve"
}
]
]
```
Response: `"f01234"`
### StateLookupRobustAddress
StateLookupRobustAddress returns the public key address of the given ID address for non-account addresses (multisig, miners etc)
Perms: read Perms: read
Inputs: Inputs:

View File

@ -0,0 +1,32 @@
package itests
import (
"context"
"testing"
"time"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/itests/kit"
"github.com/stretchr/testify/require"
)
func TestStateLookupRobustAddress(t *testing.T) {
ctx := context.Background()
kit.QuietMiningLogs()
client, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.GenesisNetworkVersion(network.Version15))
ens.InterconnectAll().BeginMining(10 * time.Millisecond)
addr, err := miner.ActorAddress(ctx)
require.NoError(t, err)
// Look up the robust address
robAddr, err := client.StateLookupRobustAddress(ctx, addr, types.EmptyTSK)
require.NoError(t, err)
// Check the id address for the given robust address and make sure it matches
idAddr, err := client.StateLookupID(ctx, robAddr, types.EmptyTSK)
require.NoError(t, err)
require.Equal(t, addr, idAddr)
}

View File

@ -449,6 +449,15 @@ func (m *StateModule) StateLookupID(ctx context.Context, addr address.Address, t
return m.StateManager.LookupID(ctx, addr, ts) return m.StateManager.LookupID(ctx, addr, ts)
} }
func (a *StateAPI) StateLookupRobustAddress(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil {
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.LookupRobustAddress(ctx, addr, ts)
}
func (m *StateModule) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) { func (m *StateModule) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
ts, err := m.Chain.GetTipSetFromKey(ctx, tsk) ts, err := m.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil { if err != nil {