Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Ipld serialization in State*Msg* RPC API #3784

Open
hanabi1224 opened this issue Dec 4, 2023 · 2 comments
Open

Fix Ipld serialization in State*Msg* RPC API #3784

hanabi1224 opened this issue Dec 4, 2023 · 2 comments
Labels
Priority: 2 - High Very important and should be addressed ASAP Type: Bug Something isn't working

Comments

@hanabi1224
Copy link
Contributor

hanabi1224 commented Dec 4, 2023

Issue summary

Lotus uses runtime reflection for IPLD serialization in RPC API json responses, it's ignored in forest for now. More investigation is needed to implement it in forest.

Related lotus code

type MsgLookup struct {
	Message   cid.Cid // Can be different than requested, in case it was replaced, but only gas values changed
	Receipt   types.MessageReceipt
	ReturnDec interface{}
	TipSet    types.TipSetKey
	Height    abi.ChainEpoch
}

var returndec interface{}
	if recpt.ExitCode == 0 && len(recpt.Return) > 0 {
		cmsg, err := m.Chain.GetCMessage(ctx, msg)
		if err != nil {
			return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err)
		}

		vmsg := cmsg.VMMessage()

		switch t, err := stmgr.GetReturnType(ctx, m.StateManager, vmsg.To, vmsg.Method, ts); {
		case errors.Is(err, stmgr.ErrMetadataNotFound):
			// This is not necessarily an error -- EVM methods (and in the future native actors) may
			// return just bytes, and in the not so distant future we'll have native wasm actors
			// that are by definition not in the registry.
			// So in this case, log a debug message and retun the raw bytes.
			log.Debugf("failed to get return type: %s", err)
			returndec = recpt.Return
		case err != nil:
			return nil, xerrors.Errorf("failed to get return type: %w", err)
		default:
			if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
				return nil, err
			}
			returndec = t
		}
	}

	return &api.MsgLookup{
		Message:   found,
		Receipt:   *recpt,
		ReturnDec: returndec,
		TipSet:    ts.Key(),
		Height:    ts.Height(),
	}, nil

func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
	act, err := sm.LoadActor(ctx, to, ts)
	if err != nil {
		return nil, xerrors.Errorf("(get sset) failed to load actor: %w", err)
	}

	m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
	if !found {
		return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, act.Code, ErrMetadataNotFound)
	}

	return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
}

example lotus API call:

request:

{
    "id": 0,
    "jsonrpc": "2.0",
    "method": "Filecoin.StateWaitMsg",
    "params": [
        {
            "/": "bafy2bzacear2xvf6lnxvtyooupaosxgh2bosn7bp35bzz6syofzk7b45gp2es"
        },
        0
    ]
}

response:

{
    "jsonrpc": "2.0",
    "result": {
        "Message": {
            "/": "bafy2bzacear2xvf6lnxvtyooupaosxgh2bosn7bp35bzz6syofzk7b45gp2es"
        },
        "Receipt": {
            "ExitCode": 0,
            "Return": "gxnmiFUCU1RCVs/3Evl82pH2EU27iJjACWtUdZ6JBkmIZWDdZSQ9ieRv0l4paI4=",
            "GasUsed": 82943114,
            "EventsRoot": null
        },
        "ReturnDec": {
            "ActorID": 59016,
            "RobustAddress": "t2knkeevwp64jps7g2sh3bctn3rcmmaclltnpwtdi",
            "EthAddress": [
                117,
                158,
                137,
                6,
                73,
                136,
                101,
                96,
                221,
                101,
                36,
                61,
                137,
                228,
                111,
                210,
                94,
                41,
                104,
                142
            ]
        },
        "TipSet": [
            {
                "/": "bafy2bzaceanaa2pyrqcn43ybv4ig5urvtumte4ftlkoaqudojyjptvtiadq7w"
            }
        ],
        "Height": 1144812
    },
    "id": 0
}

Other information and links

#3783
#3769

@lemmih lemmih mentioned this issue Dec 4, 2023
4 tasks
@aatifsyed
Copy link
Contributor

I'd love to see a more detailed explanation of the behaviour here :)

@hanabi1224
Copy link
Contributor Author

@aatifsyed I've added related lotus code to the description. Basically lotus uses any type (interface{}) for this field and use runtime reflection to serialize it with different concrete types

@lemmih lemmih added Type: Bug Something isn't working Priority: 2 - High Very important and should be addressed ASAP labels Aug 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: 2 - High Very important and should be addressed ASAP Type: Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants